Query Improvement to use entity field aliases

This commit is contained in:
Andrii Shvaika 2020-07-02 17:48:50 +03:00
commit b707ea090b
19 changed files with 245 additions and 65 deletions

View File

@ -246,6 +246,28 @@ public class UserController extends BaseController {
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/users", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<User> getUsers(
@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
SecurityUser currentUser = getCurrentUser();
if (Authority.TENANT_ADMIN.equals(currentUser.getAuthority())) {
return checkNotNull(userService.findUsersByTenantId(currentUser.getTenantId(), pageLink));
} else {
return checkNotNull(userService.findCustomerUsers(currentUser.getTenantId(), currentUser.getCustomerId(), pageLink));
}
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenant/{tenantId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody

View File

@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetId;
@ -40,6 +41,7 @@ import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.controller.HttpValidationCallback;
@ -172,6 +174,9 @@ public class AccessValidator {
case TENANT:
validateTenant(currentUser, operation, entityId, callback);
return;
case USER:
validateUser(currentUser, operation, entityId, callback);
return;
case ENTITY_VIEW:
validateEntityView(currentUser, operation, entityId, callback);
return;
@ -308,6 +313,22 @@ public class AccessValidator {
}
}
private void validateUser(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) {
ListenableFuture<User> userFuture = userService.findUserByIdAsync(currentUser.getTenantId(), new UserId(entityId.getId()));
Futures.addCallback(userFuture, getCallback(callback, user -> {
if (user == null) {
return ValidationResult.entityNotFound("User with requested id wasn't found!");
}
try {
accessControlService.checkPermission(currentUser, Resource.USER, operation, entityId, user);
} catch (ThingsboardException e) {
return ValidationResult.accessDenied(e.getMessage());
}
return ValidationResult.ok(user);
}), executor);
}
private void validateEntityView(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));

View File

@ -52,8 +52,10 @@ public interface UserService {
UserCredentials replaceUserCredentials(TenantId tenantId, UserCredentials userCredentials);
void deleteUser(TenantId tenantId, UserId userId);
PageData<User> findTenantAdmins(TenantId tenantId, PageLink pageLink);
PageData<User> findUsersByTenantId(TenantId tenantId, PageLink pageLink);
PageData<User> findTenantAdmins(TenantId tenantId, PageLink pageLink);
void deleteTenantAdmins(TenantId tenantId);

View File

@ -254,7 +254,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
String entityWhereClause = this.buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), entityFieldsFiltersMapping, entityType);
String latestJoins = EntityKeyMapping.buildLatestJoins(ctx, query.getEntityFilter(), entityType, allLatestMappings);
String whereClause = this.buildWhere(ctx, latestFiltersMapping);
String whereClause = this.buildWhere(ctx, latestFiltersMapping, query.getEntityFilter().getType(), entityType);
String textSearchQuery = this.buildTextSearchQuery(ctx, selectionMapping, pageLink.getTextSearch());
String entityFieldsSelection = EntityKeyMapping.buildSelections(entityFieldsSelectionMapping, query.getEntityFilter().getType(), entityType);
String entityTypeStr;
@ -316,7 +316,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
EntityType entityType) {
String permissionQuery = this.buildPermissionQuery(ctx, entityFilter, tenantId, customerId, entityType);
String entityFilterQuery = this.buildEntityFilterQuery(ctx, entityFilter);
String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, entityFieldsFilters);
String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, entityFieldsFilters, entityFilter.getType(), entityType);
String result = permissionQuery;
if (!entityFilterQuery.isEmpty()) {
result += " and " + entityFilterQuery;
@ -478,8 +478,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
return from;
}
private String buildWhere(QueryContext ctx, List<EntityKeyMapping> latestFiltersMapping) {
String latestFilters = EntityKeyMapping.buildQuery(ctx, latestFiltersMapping);
private String buildWhere(QueryContext ctx, List<EntityKeyMapping> latestFiltersMapping, EntityFilterType filterType, EntityType entityType) {
String latestFilters = EntityKeyMapping.buildQuery(ctx, latestFiltersMapping, filterType, entityType);
if (!StringUtils.isEmpty(latestFilters)) {
return String.format("where %s", latestFilters);
} else {

View File

@ -40,6 +40,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@ -86,7 +87,7 @@ public class EntityKeyMapping {
allowedEntityFieldMap.get(EntityType.TENANT).add(REGION);
allowedEntityFieldMap.put(EntityType.CUSTOMER, new HashSet<>(contactBasedEntityFields));
allowedEntityFieldMap.put(EntityType.USER, new HashSet<>(Arrays.asList(FIRST_NAME, LAST_NAME, EMAIL)));
allowedEntityFieldMap.put(EntityType.USER, new HashSet<>(Arrays.asList(CREATED_TIME, FIRST_NAME, LAST_NAME, EMAIL)));
allowedEntityFieldMap.put(EntityType.DASHBOARD, new HashSet<>(commonEntityFields));
allowedEntityFieldMap.put(EntityType.RULE_CHAIN, new HashSet<>(commonEntityFields));
@ -160,27 +161,8 @@ public class EntityKeyMapping {
public String toSelection(EntityFilterType filterType, EntityType entityType) {
if (entityKey.getType().equals(EntityKeyType.ENTITY_FIELD)) {
Set<String> existingEntityFields;
String alias;
if (filterType.equals(EntityFilterType.RELATIONS_QUERY)) {
existingEntityFields = relationQueryEntityFieldsSet;
alias = entityKey.getKey();
} else {
existingEntityFields = allowedEntityFieldMap.get(entityType);
if (existingEntityFields == null) {
existingEntityFields = commonEntityFieldsSet;
}
Map<String, String> entityAliases = aliases.get(entityType);
if (entityAliases != null) {
alias = entityAliases.get(entityKey.getKey());
} else {
alias = null;
}
if (alias == null) {
alias = entityKey.getKey();
}
}
Set<String> existingEntityFields = getExistingEntityFields(filterType, entityType);
String alias = getEntityFieldAlias(filterType, entityType);
if (existingEntityFields.contains(alias)) {
String column = entityFieldColumnMap.get(alias);
return String.format("e.%s as %s", column, getValueAlias());
@ -194,11 +176,48 @@ public class EntityKeyMapping {
}
}
public Stream<String> toQueries(QueryContext ctx) {
private String getEntityFieldAlias(EntityFilterType filterType, EntityType entityType) {
String alias;
if (filterType.equals(EntityFilterType.RELATIONS_QUERY)) {
alias = entityKey.getKey();
} else {
alias = getAliasByEntityKeyAndType(entityKey.getKey(), entityType);
}
return alias;
}
private Set<String> getExistingEntityFields(EntityFilterType filterType, EntityType entityType) {
Set<String> existingEntityFields;
if (filterType.equals(EntityFilterType.RELATIONS_QUERY)) {
existingEntityFields = relationQueryEntityFieldsSet;
} else {
existingEntityFields = allowedEntityFieldMap.get(entityType);
if (existingEntityFields == null) {
existingEntityFields = commonEntityFieldsSet;
}
}
return existingEntityFields;
}
private String getAliasByEntityKeyAndType(String key, EntityType entityType) {
String alias;
Map<String, String> entityAliases = aliases.get(entityType);
if (entityAliases != null) {
alias = entityAliases.get(key);
} else {
alias = null;
}
if (alias == null) {
alias = key;
}
return alias;
}
public Stream<String> toQueries(QueryContext ctx, EntityFilterType filterType, EntityType entityType) {
if (hasFilter()) {
String keyAlias = entityKey.getType().equals(EntityKeyType.ENTITY_FIELD) ? "e" : alias;
return keyFilters.stream().map(keyFilter ->
this.buildKeyQuery(ctx, keyAlias, keyFilter));
this.buildKeyQuery(ctx, keyAlias, keyFilter, filterType, entityType));
} else {
return null;
}
@ -244,8 +263,8 @@ public class EntityKeyMapping {
Collectors.joining(" "));
}
public static String buildQuery(QueryContext ctx, List<EntityKeyMapping> mappings) {
return mappings.stream().flatMap(mapping -> mapping.toQueries(ctx)).collect(
public static String buildQuery(QueryContext ctx, List<EntityKeyMapping> mappings, EntityFilterType filterType, EntityType entityType) {
return mappings.stream().flatMap(mapping -> mapping.toQueries(ctx, filterType, entityType)).filter(Objects::nonNull).collect(
Collectors.joining(" AND "));
}
@ -357,47 +376,63 @@ public class EntityKeyMapping {
return String.join(", ", attrValSelection, attrTsSelection);
}
private String buildKeyQuery(QueryContext ctx, String alias, KeyFilter keyFilter) {
return this.buildPredicateQuery(ctx, alias, keyFilter.getKey(), keyFilter.getPredicate());
private String buildKeyQuery(QueryContext ctx, String alias, KeyFilter keyFilter,
EntityFilterType filterType, EntityType entityType) {
return this.buildPredicateQuery(ctx, alias, keyFilter.getKey(), keyFilter.getPredicate(), filterType, entityType);
}
private String buildPredicateQuery(QueryContext ctx, String alias, EntityKey key, KeyFilterPredicate predicate) {
private String buildPredicateQuery(QueryContext ctx, String alias, EntityKey key,
KeyFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) {
if (predicate.getType().equals(FilterPredicateType.COMPLEX)) {
return this.buildComplexPredicateQuery(ctx, alias, key, (ComplexFilterPredicate) predicate);
return this.buildComplexPredicateQuery(ctx, alias, key, (ComplexFilterPredicate) predicate, filterType, entityType);
} else {
return this.buildSimplePredicateQuery(ctx, alias, key, predicate);
return this.buildSimplePredicateQuery(ctx, alias, key, predicate, filterType, entityType);
}
}
private String buildComplexPredicateQuery(QueryContext ctx, String alias, EntityKey key, ComplexFilterPredicate predicate) {
private String buildComplexPredicateQuery(QueryContext ctx, String alias, EntityKey key,
ComplexFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) {
return predicate.getPredicates().stream()
.map(keyFilterPredicate -> this.buildPredicateQuery(ctx, alias, key, keyFilterPredicate)).collect(Collectors.joining(
.map(keyFilterPredicate -> this.buildPredicateQuery(ctx, alias, key, keyFilterPredicate, filterType, entityType))
.filter(Objects::nonNull).collect(Collectors.joining(
" " + predicate.getOperation().name() + " "
));
}
private String buildSimplePredicateQuery(QueryContext ctx, String alias, EntityKey key, KeyFilterPredicate predicate) {
if (predicate.getType().equals(FilterPredicateType.NUMERIC)) {
if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) {
String column = entityFieldColumnMap.get(key.getKey());
return this.buildNumericPredicateQuery(ctx, alias + "." + column, (NumericFilterPredicate) predicate);
private String buildSimplePredicateQuery(QueryContext ctx, String alias, EntityKey key,
KeyFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) {
if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) {
Set<String> existingEntityFields = getExistingEntityFields(filterType, entityType);
String entityFieldAlias = getEntityFieldAlias(filterType, entityType);
String column = null;
if (existingEntityFields.contains(entityFieldAlias)) {
column = entityFieldColumnMap.get(key.getKey());
}
if (column != null) {
String field = alias + "." + column;
if (predicate.getType().equals(FilterPredicateType.NUMERIC)) {
return this.buildNumericPredicateQuery(ctx, field, (NumericFilterPredicate) predicate);
} else if (predicate.getType().equals(FilterPredicateType.STRING)) {
return this.buildStringPredicateQuery(ctx, field, (StringFilterPredicate) predicate);
} else {
return this.buildBooleanPredicateQuery(ctx, field, (BooleanFilterPredicate) predicate);
}
} else {
return null;
}
} else {
if (predicate.getType().equals(FilterPredicateType.NUMERIC)) {
String longQuery = this.buildNumericPredicateQuery(ctx, alias + ".long_v", (NumericFilterPredicate) predicate);
String doubleQuery = this.buildNumericPredicateQuery(ctx, alias + ".dbl_v", (NumericFilterPredicate) predicate);
return String.format("(%s or %s)", longQuery, doubleQuery);
}
} else {
String column;
if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) {
column = entityFieldColumnMap.get(key.getKey());
} else {
column = predicate.getType().equals(FilterPredicateType.STRING) ? "str_v" : "bool_v";
}
String field = alias + "." + column;
if (predicate.getType().equals(FilterPredicateType.STRING)) {
return this.buildStringPredicateQuery(ctx, field, (StringFilterPredicate) predicate);
} else {
return this.buildBooleanPredicateQuery(ctx, field, (BooleanFilterPredicate) predicate);
String column = predicate.getType().equals(FilterPredicateType.STRING) ? "str_v" : "bool_v";
String field = alias + "." + column;
if (predicate.getType().equals(FilterPredicateType.STRING)) {
return this.buildStringPredicateQuery(ctx, field, (StringFilterPredicate) predicate);
} else {
return this.buildBooleanPredicateQuery(ctx, field, (BooleanFilterPredicate) predicate);
}
}
}
}

View File

@ -59,6 +59,16 @@ public class JpaUserDao extends JpaAbstractSearchTextDao<UserEntity, User> imple
return DaoUtil.getData(userRepository.findByEmail(email));
}
@Override
public PageData<User> findByTenantId(UUID tenantId, PageLink pageLink) {
return DaoUtil.toPageData(
userRepository
.findByTenantId(
tenantId,
Objects.toString(pageLink.getTextSearch(), ""),
DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<User> findTenantAdmins(UUID tenantId, PageLink pageLink) {
return DaoUtil.toPageData(

View File

@ -43,4 +43,10 @@ public interface UserRepository extends PagingAndSortingRepository<UserEntity, U
@Param("authority") Authority authority,
Pageable pageable);
@Query("SELECT u FROM UserEntity u WHERE u.tenantId = :tenantId " +
"AND LOWER(u.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
Page<UserEntity> findByTenantId(@Param("tenantId") UUID tenantId,
@Param("searchText") String searchText,
Pageable pageable);
}

View File

@ -40,6 +40,15 @@ public interface UserDao extends Dao<User> {
* @return the user entity
*/
User findByEmail(TenantId tenantId, String email);
/**
* Find users by tenantId and page link.
*
* @param tenantId the tenantId
* @param pageLink the page link
* @return the list of user entities
*/
PageData<User> findByTenantId(UUID tenantId, PageLink pageLink);
/**
* Find tenant admin users by tenantId and page link.

View File

@ -219,6 +219,14 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
userDao.removeById(tenantId, userId.getId());
}
@Override
public PageData<User> findUsersByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findUsersByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
validatePageLink(pageLink);
return userDao.findByTenantId(tenantId.getId(), pageLink);
}
@Override
public PageData<User> findTenantAdmins(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findTenantAdmins, tenantId [{}], pageLink [{}]", tenantId, pageLink);

View File

@ -310,7 +310,8 @@ export class EntityService {
}
break;
case EntityType.USER:
console.error('Get User Entities is not implemented!');
pageLink.sortOrder.property = 'email';
entitiesObservable = this.userService.getUsers(pageLink);
break;
case EntityType.ALARM:
console.error('Get Alarm Entities is not implemented!');
@ -548,6 +549,7 @@ export class EntityService {
entityTypes.push(EntityType.ENTITY_VIEW);
entityTypes.push(EntityType.TENANT);
entityTypes.push(EntityType.CUSTOMER);
entityTypes.push(EntityType.USER);
entityTypes.push(EntityType.DASHBOARD);
if (useAliasEntityTypes) {
entityTypes.push(AliasEntityType.CURRENT_CUSTOMER);
@ -559,12 +561,16 @@ export class EntityService {
entityTypes.push(EntityType.ASSET);
entityTypes.push(EntityType.ENTITY_VIEW);
entityTypes.push(EntityType.CUSTOMER);
entityTypes.push(EntityType.USER);
entityTypes.push(EntityType.DASHBOARD);
if (useAliasEntityTypes) {
entityTypes.push(AliasEntityType.CURRENT_CUSTOMER);
}
break;
}
if (useAliasEntityTypes) {
entityTypes.push(AliasEntityType.CURRENT_USER);
}
if (allowedEntityTypes && allowedEntityTypes.length) {
for (let index = entityTypes.length - 1; index >= 0; index--) {
if (allowedEntityTypes.indexOf(entityTypes[index]) === -1) {
@ -961,6 +967,10 @@ export class EntityService {
const authUser = getCurrentAuthUser(this.store);
entityId.entityType = EntityType.TENANT;
entityId.id = authUser.tenantId;
} else if (entityType === AliasEntityType.CURRENT_USER){
const authUser = getCurrentAuthUser(this.store);
entityId.entityType = EntityType.USER;
entityId.id = authUser.userId;
}
return entityId;
}

View File

@ -32,6 +32,12 @@ export class UserService {
private http: HttpClient
) { }
public getUsers(pageLink: PageLink,
config?: RequestConfig): Observable<PageData<User>> {
return this.http.get<PageData<User>>(`/api/users${pageLink.toQuery()}`,
defaultHttpOptionsFromConfig(config));
}
public getTenantAdmins(tenantId: string, pageLink: PageLink,
config?: RequestConfig): Observable<PageData<User>> {
return this.http.get<PageData<User>>(`/api/tenant/${tenantId}/users${pageLink.toQuery()}`,

View File

@ -28,6 +28,7 @@ import {
AliasesEntitySelectPanelData
} from './aliases-entity-select-panel.component';
import { deepClone } from '@core/utils';
import { AliasFilterType } from '@shared/models/alias.models';
@Component({
selector: 'tb-aliases-entity-select',
@ -178,7 +179,7 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
for (const aliasId of Object.keys(allEntityAliases)) {
const aliasInfo = this.aliasController.getInstantAliasInfo(aliasId);
if (aliasInfo && !aliasInfo.resolveMultiple && aliasInfo.currentEntity
&& aliasInfo.entityFilter) {
&& aliasInfo.entityFilter && aliasInfo.entityFilter.type !== AliasFilterType.singleEntity) {
this.entityAliasesInfo[aliasId] = deepClone(aliasInfo);
this.hasSelectableAliasEntities = true;
}

View File

@ -84,6 +84,9 @@ import {
KeyFilter
} from '@shared/models/query/query.models';
import { sortItems } from '@shared/models/page/page-link';
import { entityFields } from '@shared/models/entity.models';
import { alarmFields } from '@shared/models/alarm.models';
import { DatePipe } from '@angular/common';
interface EntitiesTableWidgetSettings extends TableWidgetSettings {
entitiesTitle: string;
@ -153,6 +156,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
private overlay: Overlay,
private viewContainerRef: ViewContainerRef,
private utils: UtilsService,
private datePipe: DatePipe,
private translate: TranslateService,
private domSanitizer: DomSanitizer) {
super(store);
@ -511,9 +515,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
content = '' + value;
}
} else {
const decimals = (contentInfo.decimals || contentInfo.decimals === 0) ? contentInfo.decimals : this.ctx.widgetConfig.decimals;
const units = contentInfo.units || this.ctx.widgetConfig.units;
content = this.ctx.utils.formatValue(value, decimals, units, true);
content = this.defaultContent(key, contentInfo, value);
}
return isDefined(content) ? this.domSanitizer.bypassSecurityTrustHtml(content) : '';
} else {
@ -521,6 +523,22 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
}
}
private defaultContent(key: EntityColumn, contentInfo: CellContentInfo, value: any): any {
if (isDefined(value)) {
const entityField = entityFields[key.name];
if (entityField) {
if (entityField.time) {
return this.datePipe.transform(value, 'yyyy-MM-dd HH:mm:ss');
}
}
const decimals = (contentInfo.decimals || contentInfo.decimals === 0) ? contentInfo.decimals : this.ctx.widgetConfig.decimals;
const units = contentInfo.units || this.ctx.widgetConfig.units;
return this.ctx.utils.formatValue(value, decimals, units, true);
} else {
return '';
}
}
public onRowClick($event: Event, entity: EntityData, isDouble?: boolean) {
if ($event) {
$event.stopPropagation();

View File

@ -15,6 +15,23 @@
limitations under the License.
-->
<mat-tab *ngIf="entity"
label="{{ 'attribute.attributes' | translate }}" #attributesTab="matTab">
<tb-attribute-table [defaultAttributeScope]="attributeScopes.SERVER_SCOPE"
[active]="attributesTab.isActive"
[entityId]="entity.id"
[entityName]="entity.name">
</tb-attribute-table>
</mat-tab>
<mat-tab *ngIf="entity"
label="{{ 'attribute.latest-telemetry' | translate }}" #telemetryTab="matTab">
<tb-attribute-table [defaultAttributeScope]="latestTelemetryTypes.LATEST_TELEMETRY"
disableAttributeScopeSelection
[active]="telemetryTab.isActive"
[entityId]="entity.id"
[entityName]="entity.name">
</tb-attribute-table>
</mat-tab>
<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN"
label="{{ 'audit-log.audit-logs' | translate }}" #auditLogsTab="matTab">
<tb-audit-log-table [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.USER" [userId]="entity.id" detailsMode="true"></tb-audit-log-table>

View File

@ -175,6 +175,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit
this.entityRequiredText = 'customer.customer-required';
break;
case EntityType.USER:
case AliasEntityType.CURRENT_USER:
this.entityText = 'user.user';
this.noEntitiesMatchingText = 'user.no-users-matching';
this.entityRequiredText = 'user.user-required';
@ -324,6 +325,8 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit
return EntityType.CUSTOMER;
} else if (entityType === AliasEntityType.CURRENT_TENANT) {
return EntityType.TENANT;
} else if (entityType === AliasEntityType.CURRENT_USER) {
return EntityType.USER;
}
return entityType;
}

View File

@ -27,7 +27,8 @@
</tb-entity-type-select>
<tb-entity-autocomplete
fxFlex
*ngIf="modelValue.entityType && modelValue.entityType !== AliasEntityType.CURRENT_TENANT"
*ngIf="modelValue.entityType && modelValue.entityType !== AliasEntityType.CURRENT_TENANT
&& modelValue.entityType !== AliasEntityType.CURRENT_USER"
[required]="required"
[entityType]="modelValue.entityType"
formControlName="entityId">

View File

@ -97,7 +97,7 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte
ngOnInit() {
this.entitySelectFormGroup.get('entityType').valueChanges.subscribe(
(value) => {
if(value === AliasEntityType.CURRENT_TENANT){
if(value === AliasEntityType.CURRENT_TENANT || value === AliasEntityType.CURRENT_USER) {
this.modelValue.id = NULL_UUID;
}
this.updateView(value, this.modelValue.id);
@ -145,7 +145,9 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte
entityType,
id: this.modelValue.entityType !== entityType ? null : entityId
};
if (this.modelValue.entityType && (this.modelValue.id || this.modelValue.entityType === AliasEntityType.CURRENT_TENANT)) {
if (this.modelValue.entityType && (this.modelValue.id ||
this.modelValue.entityType === AliasEntityType.CURRENT_TENANT ||
this.modelValue.entityType === AliasEntityType.CURRENT_USER)) {
this.propagateChange(this.modelValue);
} else {
this.propagateChange(null);

View File

@ -50,7 +50,8 @@ export enum EntityType {
export enum AliasEntityType {
CURRENT_CUSTOMER = 'CURRENT_CUSTOMER',
CURRENT_TENANT = 'CURRENT_TENANT'
CURRENT_TENANT = 'CURRENT_TENANT',
CURRENT_USER = 'CURRENT_USER'
}
export interface EntityTypeTranslation {
@ -229,6 +230,13 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti
type: 'entity.type-current-tenant',
list: 'entity.type-current-tenant'
}
],
[
AliasEntityType.CURRENT_USER,
{
type: 'entity.type-current-user',
list: 'entity.type-current-user'
}
]
]
);

View File

@ -841,6 +841,7 @@
"rulenode-name-starts-with": "Rule nodes whose names start with '{{prefix}}'",
"type-current-customer": "Current Customer",
"type-current-tenant": "Current Tenant",
"type-current-user": "Current User",
"search": "Search entities",
"selected-entities": "{ count, plural, 1 {1 entity} other {# entities} } selected",
"entity-name": "Entity name",