tenant configuration changes
This commit is contained in:
parent
e6309a8885
commit
ddbf83479d
|
@ -55,3 +55,4 @@ dmp-backend/web/src/main/resources/certificates/
|
||||||
dmp-backend/target/classes/
|
dmp-backend/target/classes/
|
||||||
dmp-backend/core/target/maven-archiver/
|
dmp-backend/core/target/maven-archiver/
|
||||||
dmp-backend/node_modules/.yarn-integrity
|
dmp-backend/node_modules/.yarn-integrity
|
||||||
|
dmp-frontend/.nx/
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
package eu.eudat.authorization;
|
package eu.eudat.authorization;
|
||||||
|
|
||||||
public final class Permission {
|
public final class Permission {
|
||||||
/////// Should Remove after Refactor
|
|
||||||
|
|
||||||
public static String AdminRole = "AdminRole";
|
|
||||||
public static String AuthenticatedRole = "AuthenticatedRole";
|
|
||||||
|
|
||||||
/////
|
/////
|
||||||
public static String DeferredAffiliation = "DeferredAffiliation";
|
public static String DeferredAffiliation = "DeferredAffiliation";
|
||||||
|
|
||||||
|
@ -222,5 +217,6 @@ public final class Permission {
|
||||||
public static String ViewMyDmpPage = "ViewMyDmpPage";
|
public static String ViewMyDmpPage = "ViewMyDmpPage";
|
||||||
public static String ViewHomePage = "ViewHomePage";
|
public static String ViewHomePage = "ViewHomePage";
|
||||||
public static String ViewMineInAppNotificationPage = "ViewMineInAppNotificationPage";
|
public static String ViewMineInAppNotificationPage = "ViewMineInAppNotificationPage";
|
||||||
|
public static String ViewTenantConfigurationPage = "ViewTenantConfigurationPage";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,4 +184,14 @@ public class ErrorThesaurusProperties {
|
||||||
public void setTenantConfigurationTypeCanNotChange(ErrorDescription tenantConfigurationTypeCanNotChange) {
|
public void setTenantConfigurationTypeCanNotChange(ErrorDescription tenantConfigurationTypeCanNotChange) {
|
||||||
this.tenantConfigurationTypeCanNotChange = tenantConfigurationTypeCanNotChange;
|
this.tenantConfigurationTypeCanNotChange = tenantConfigurationTypeCanNotChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ErrorDescription multipleTenantConfigurationTypeNotAllowed;
|
||||||
|
|
||||||
|
public ErrorDescription getMultipleTenantConfigurationTypeNotAllowed() {
|
||||||
|
return multipleTenantConfigurationTypeNotAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMultipleTenantConfigurationTypeNotAllowed(ErrorDescription multipleTenantConfigurationTypeNotAllowed) {
|
||||||
|
this.multipleTenantConfigurationTypeNotAllowed = multipleTenantConfigurationTypeNotAllowed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,19 +157,19 @@ public class TenantConfigurationPersist {
|
||||||
.must(() -> !this.isNull(item.getCssColors()))
|
.must(() -> !this.isNull(item.getCssColors()))
|
||||||
.failOn(TenantConfigurationPersist._cssColors).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._cssColors}, LocaleContextHolder.getLocale())),
|
.failOn(TenantConfigurationPersist._cssColors).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._cssColors}, LocaleContextHolder.getLocale())),
|
||||||
this.spec()
|
this.spec()
|
||||||
.iff(() -> !this.isNull(item.getType()) && TenantConfigurationType.CssColors.equals(item.getType()))
|
.iff(() -> !this.isNull(item.getType()) && TenantConfigurationType.DefaultUserLocale.equals(item.getType()))
|
||||||
.must(() -> !this.isNull(item.getDefaultUserLocale()))
|
.must(() -> !this.isNull(item.getDefaultUserLocale()))
|
||||||
.failOn(TenantConfigurationPersist._defaultUserLocale).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._defaultUserLocale}, LocaleContextHolder.getLocale())),
|
.failOn(TenantConfigurationPersist._defaultUserLocale).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._defaultUserLocale}, LocaleContextHolder.getLocale())),
|
||||||
this.spec()
|
this.spec()
|
||||||
.iff(() -> !this.isNull(item.getType()) && TenantConfigurationType.CssColors.equals(item.getType()))
|
.iff(() -> !this.isNull(item.getType()) && TenantConfigurationType.DepositPlugins.equals(item.getType()))
|
||||||
.must(() -> !this.isNull(item.getDepositPlugins()))
|
.must(() -> !this.isNull(item.getDepositPlugins()))
|
||||||
.failOn(TenantConfigurationPersist._depositPlugins).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._depositPlugins}, LocaleContextHolder.getLocale())),
|
.failOn(TenantConfigurationPersist._depositPlugins).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._depositPlugins}, LocaleContextHolder.getLocale())),
|
||||||
this.spec()
|
this.spec()
|
||||||
.iff(() -> !this.isNull(item.getType()) && TenantConfigurationType.CssColors.equals(item.getType()))
|
.iff(() -> !this.isNull(item.getType()) && TenantConfigurationType.FileTransformerPlugins.equals(item.getType()))
|
||||||
.must(() -> !this.isNull(item.getFileTransformerPlugins()))
|
.must(() -> !this.isNull(item.getFileTransformerPlugins()))
|
||||||
.failOn(TenantConfigurationPersist._fileTransformerPlugins).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._fileTransformerPlugins}, LocaleContextHolder.getLocale())),
|
.failOn(TenantConfigurationPersist._fileTransformerPlugins).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._fileTransformerPlugins}, LocaleContextHolder.getLocale())),
|
||||||
this.spec()
|
this.spec()
|
||||||
.iff(() -> !this.isNull(item.getType()) && TenantConfigurationType.CssColors.equals(item.getType()))
|
.iff(() -> !this.isNull(item.getType()) && TenantConfigurationType.Logo.equals(item.getType()))
|
||||||
.must(() -> !this.isNull(item.getLogo()))
|
.must(() -> !this.isNull(item.getLogo()))
|
||||||
.failOn(TenantConfigurationPersist._logo).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._logo}, LocaleContextHolder.getLocale())),
|
.failOn(TenantConfigurationPersist._logo).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._logo}, LocaleContextHolder.getLocale())),
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,14 @@ import eu.eudat.model.persist.deposit.DepositSourcePersist;
|
||||||
import eu.eudat.model.persist.filetransformer.FileTransformerSourcePersist;
|
import eu.eudat.model.persist.filetransformer.FileTransformerSourcePersist;
|
||||||
import eu.eudat.model.persist.tenantconfiguration.*;
|
import eu.eudat.model.persist.tenantconfiguration.*;
|
||||||
import eu.eudat.model.tenantconfiguration.TenantConfiguration;
|
import eu.eudat.model.tenantconfiguration.TenantConfiguration;
|
||||||
|
import eu.eudat.query.TenantConfigurationQuery;
|
||||||
import eu.eudat.service.encryption.EncryptionService;
|
import eu.eudat.service.encryption.EncryptionService;
|
||||||
import eu.eudat.service.storage.StorageFileService;
|
import eu.eudat.service.storage.StorageFileService;
|
||||||
import eu.eudat.service.tenant.TenantProperties;
|
import eu.eudat.service.tenant.TenantProperties;
|
||||||
import gr.cite.commons.web.authz.service.AuthorizationService;
|
import gr.cite.commons.web.authz.service.AuthorizationService;
|
||||||
import gr.cite.tools.data.builder.BuilderFactory;
|
import gr.cite.tools.data.builder.BuilderFactory;
|
||||||
import gr.cite.tools.data.deleter.DeleterFactory;
|
import gr.cite.tools.data.deleter.DeleterFactory;
|
||||||
|
import gr.cite.tools.data.query.QueryFactory;
|
||||||
import gr.cite.tools.exception.MyApplicationException;
|
import gr.cite.tools.exception.MyApplicationException;
|
||||||
import gr.cite.tools.exception.MyForbiddenException;
|
import gr.cite.tools.exception.MyForbiddenException;
|
||||||
import gr.cite.tools.exception.MyNotFoundException;
|
import gr.cite.tools.exception.MyNotFoundException;
|
||||||
|
@ -79,6 +81,7 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
|
||||||
|
|
||||||
private final TenantProperties tenantProperties;
|
private final TenantProperties tenantProperties;
|
||||||
private final StorageFileService storageFileService;
|
private final StorageFileService storageFileService;
|
||||||
|
private final QueryFactory queryFactory;
|
||||||
@Autowired
|
@Autowired
|
||||||
public TenantConfigurationServiceImpl(
|
public TenantConfigurationServiceImpl(
|
||||||
TenantEntityManager entityManager,
|
TenantEntityManager entityManager,
|
||||||
|
@ -87,7 +90,7 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
|
||||||
BuilderFactory builderFactory,
|
BuilderFactory builderFactory,
|
||||||
ConventionService conventionService,
|
ConventionService conventionService,
|
||||||
ErrorThesaurusProperties errors,
|
ErrorThesaurusProperties errors,
|
||||||
MessageSource messageSource, JsonHandlingService jsonHandlingService, EncryptionService encryptionService, TenantProperties tenantProperties, StorageFileService storageFileService) {
|
MessageSource messageSource, JsonHandlingService jsonHandlingService, EncryptionService encryptionService, TenantProperties tenantProperties, StorageFileService storageFileService, QueryFactory queryFactory) {
|
||||||
this.entityManager = entityManager;
|
this.entityManager = entityManager;
|
||||||
this.authorizationService = authorizationService;
|
this.authorizationService = authorizationService;
|
||||||
this.deleterFactory = deleterFactory;
|
this.deleterFactory = deleterFactory;
|
||||||
|
@ -99,6 +102,7 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
|
||||||
this.encryptionService = encryptionService;
|
this.encryptionService = encryptionService;
|
||||||
this.tenantProperties = tenantProperties;
|
this.tenantProperties = tenantProperties;
|
||||||
this.storageFileService = storageFileService;
|
this.storageFileService = storageFileService;
|
||||||
|
this.queryFactory = queryFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TenantConfiguration persist(TenantConfigurationPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
|
public TenantConfiguration persist(TenantConfigurationPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
|
||||||
|
@ -122,6 +126,10 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
|
||||||
data.setType(model.getType());
|
data.setType(model.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TenantConfigurationQuery tenantConfigurationQuery = this.queryFactory.query(TenantConfigurationQuery.class).excludedIds(data.getId()).isActive(IsActive.Active).types(data.getType());
|
||||||
|
if (data.getTenantId() == null) tenantConfigurationQuery.tenantIsSet(false);
|
||||||
|
else tenantConfigurationQuery.tenantIsSet(false).tenantIds(data.getTenantId());
|
||||||
|
if (tenantConfigurationQuery.count() > 0)throw new MyValidationException(this.errors.getMultipleTenantConfigurationTypeNotAllowed().getCode(), this.errors.getMultipleTenantConfigurationTypeNotAllowed().getMessage());
|
||||||
|
|
||||||
switch (data.getType()){
|
switch (data.getType()){
|
||||||
case CssColors -> data.setValue(this.jsonHandlingService.toJson(this.buildCssColorsTenantConfigurationEntity(model.getCssColors())));
|
case CssColors -> data.setValue(this.jsonHandlingService.toJson(this.buildCssColorsTenantConfigurationEntity(model.getCssColors())));
|
||||||
|
|
|
@ -3,6 +3,9 @@ package eu.eudat.controllers;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import eu.eudat.audit.AuditableAction;
|
import eu.eudat.audit.AuditableAction;
|
||||||
import eu.eudat.authorization.AuthorizationFlags;
|
import eu.eudat.authorization.AuthorizationFlags;
|
||||||
|
import eu.eudat.commons.enums.IsActive;
|
||||||
|
import eu.eudat.commons.enums.TenantConfigurationType;
|
||||||
|
import eu.eudat.commons.scope.tenant.TenantScope;
|
||||||
import eu.eudat.data.TenantConfigurationEntity;
|
import eu.eudat.data.TenantConfigurationEntity;
|
||||||
import eu.eudat.model.DescriptionTemplateType;
|
import eu.eudat.model.DescriptionTemplateType;
|
||||||
import eu.eudat.model.builder.tenantconfiguration.TenantConfigurationBuilder;
|
import eu.eudat.model.builder.tenantconfiguration.TenantConfigurationBuilder;
|
||||||
|
@ -56,23 +59,25 @@ public class TenantConfigurationController {
|
||||||
private final QueryFactory queryFactory;
|
private final QueryFactory queryFactory;
|
||||||
|
|
||||||
private final MessageSource messageSource;
|
private final MessageSource messageSource;
|
||||||
|
private final TenantScope tenantScope;
|
||||||
|
|
||||||
public TenantConfigurationController(
|
public TenantConfigurationController(
|
||||||
BuilderFactory builderFactory,
|
BuilderFactory builderFactory,
|
||||||
AuditService auditService,
|
AuditService auditService,
|
||||||
TenantConfigurationService tenantConfigurationService, CensorFactory censorFactory,
|
TenantConfigurationService tenantConfigurationService, CensorFactory censorFactory,
|
||||||
QueryFactory queryFactory,
|
QueryFactory queryFactory,
|
||||||
MessageSource messageSource) {
|
MessageSource messageSource, TenantScope tenantScope) {
|
||||||
this.builderFactory = builderFactory;
|
this.builderFactory = builderFactory;
|
||||||
this.auditService = auditService;
|
this.auditService = auditService;
|
||||||
this.tenantConfigurationService = tenantConfigurationService;
|
this.tenantConfigurationService = tenantConfigurationService;
|
||||||
this.censorFactory = censorFactory;
|
this.censorFactory = censorFactory;
|
||||||
this.queryFactory = queryFactory;
|
this.queryFactory = queryFactory;
|
||||||
this.messageSource = messageSource;
|
this.messageSource = messageSource;
|
||||||
|
this.tenantScope = tenantScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("query")
|
@PostMapping("query")
|
||||||
public QueryResult<TenantConfiguration> Query(@RequestBody TenantConfigurationLookup lookup) throws MyApplicationException, MyForbiddenException {
|
public QueryResult<TenantConfiguration> query(@RequestBody TenantConfigurationLookup lookup) throws MyApplicationException, MyForbiddenException {
|
||||||
logger.debug("querying {}", TenantConfiguration.class.getSimpleName());
|
logger.debug("querying {}", TenantConfiguration.class.getSimpleName());
|
||||||
|
|
||||||
this.censorFactory.censor(TenantConfigurationCensor.class).censor(lookup.getProject(), null);
|
this.censorFactory.censor(TenantConfigurationCensor.class).censor(lookup.getProject(), null);
|
||||||
|
@ -89,7 +94,7 @@ public class TenantConfigurationController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("{id}")
|
@GetMapping("{id}")
|
||||||
public TenantConfiguration Get(@PathVariable("id") UUID id, FieldSet fieldSet, Locale locale) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
|
public TenantConfiguration get(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
|
||||||
logger.debug(new MapLogEntry("retrieving" + TenantConfiguration.class.getSimpleName()).And("id", id).And("fields", fieldSet));
|
logger.debug(new MapLogEntry("retrieving" + TenantConfiguration.class.getSimpleName()).And("id", id).And("fields", fieldSet));
|
||||||
|
|
||||||
this.censorFactory.censor(TenantConfigurationCensor.class).censor(fieldSet, null);
|
this.censorFactory.censor(TenantConfigurationCensor.class).censor(fieldSet, null);
|
||||||
|
@ -107,10 +112,30 @@ public class TenantConfigurationController {
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("current-tenant/{type}")
|
||||||
|
public TenantConfiguration getCurrentTenantType(@PathVariable("type") Short type, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException {
|
||||||
|
logger.debug(new MapLogEntry("retrieving" + TenantConfiguration.class.getSimpleName()).And("type", type).And("fields", fieldSet));
|
||||||
|
|
||||||
|
this.censorFactory.censor(TenantConfigurationCensor.class).censor(fieldSet, null);
|
||||||
|
|
||||||
|
TenantConfigurationQuery query = this.queryFactory.query(TenantConfigurationQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).isActive(IsActive.Active).types(TenantConfigurationType.of(type));
|
||||||
|
if (this.tenantScope.isDefaultTenant()) query.tenantIsSet(false);
|
||||||
|
else query.tenantIsSet(false).tenantIds(this.tenantScope.getTenant());
|
||||||
|
|
||||||
|
TenantConfiguration model = this.builderFactory.builder(TenantConfigurationBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(fieldSet, query.firstAs(fieldSet));
|
||||||
|
|
||||||
|
this.auditService.track(AuditableAction.TenantConfiguration_Lookup, Map.ofEntries(
|
||||||
|
new AbstractMap.SimpleEntry<String, Object>("type", type),
|
||||||
|
new AbstractMap.SimpleEntry<String, Object>("fields", fieldSet)
|
||||||
|
));
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("persist")
|
@PostMapping("persist")
|
||||||
@Transactional
|
@Transactional
|
||||||
@ValidationFilterAnnotation(validator = TenantConfigurationPersist.TenantConfigurationPersistValidator.ValidatorName, argumentName = "model")
|
@ValidationFilterAnnotation(validator = TenantConfigurationPersist.TenantConfigurationPersistValidator.ValidatorName, argumentName = "model")
|
||||||
public TenantConfiguration Persist(@RequestBody TenantConfigurationPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
|
public TenantConfiguration persist(@RequestBody TenantConfigurationPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
|
||||||
logger.debug(new MapLogEntry("persisting" + DescriptionTemplateType.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet));
|
logger.debug(new MapLogEntry("persisting" + DescriptionTemplateType.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet));
|
||||||
TenantConfiguration persisted = this.tenantConfigurationService.persist(model, fieldSet);
|
TenantConfiguration persisted = this.tenantConfigurationService.persist(model, fieldSet);
|
||||||
|
|
||||||
|
@ -124,7 +149,7 @@ public class TenantConfigurationController {
|
||||||
|
|
||||||
@DeleteMapping("{id}")
|
@DeleteMapping("{id}")
|
||||||
@Transactional
|
@Transactional
|
||||||
public void Delete(@PathVariable("id") UUID id) throws MyForbiddenException, InvalidApplicationException {
|
public void delete(@PathVariable("id") UUID id) throws MyForbiddenException, InvalidApplicationException {
|
||||||
logger.debug(new MapLogEntry("retrieving" + TenantConfiguration.class.getSimpleName()).And("id", id));
|
logger.debug(new MapLogEntry("retrieving" + TenantConfiguration.class.getSimpleName()).And("id", id));
|
||||||
|
|
||||||
this.tenantConfigurationService.deleteAndSave(id);
|
this.tenantConfigurationService.deleteAndSave(id);
|
||||||
|
|
|
@ -62,4 +62,7 @@ error-thesaurus:
|
||||||
tenant-configuration-type-can-not-change:
|
tenant-configuration-type-can-not-change:
|
||||||
code: 124
|
code: 124
|
||||||
message: Tenant configuration type can not change
|
message: Tenant configuration type can not change
|
||||||
|
multiple-tenant-configuration-type-not-allowed:
|
||||||
|
code: 125
|
||||||
|
message: Multiple Tenant Configuration Type Not Allowed
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,6 @@
|
||||||
permissions:
|
permissions:
|
||||||
extendedClaims: [ ]
|
extendedClaims: [ ]
|
||||||
policies:
|
policies:
|
||||||
###### Should Remove after Refactor
|
|
||||||
AdminRole:
|
|
||||||
roles:
|
|
||||||
- Admin
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
AuthenticatedRole:
|
|
||||||
roles: []
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: true
|
|
||||||
|
|
||||||
######
|
|
||||||
# Affiliation
|
# Affiliation
|
||||||
DeferredAffiliation:
|
DeferredAffiliation:
|
||||||
roles:
|
roles:
|
||||||
|
@ -1028,3 +1014,10 @@ permissions:
|
||||||
clients: [ ]
|
clients: [ ]
|
||||||
allowAnonymous: false
|
allowAnonymous: false
|
||||||
allowAuthenticated: true
|
allowAuthenticated: true
|
||||||
|
ViewTenantConfigurationPage:
|
||||||
|
roles:
|
||||||
|
- TenantAdmin
|
||||||
|
- Admin
|
||||||
|
clients: [ ]
|
||||||
|
allowAnonymous: false
|
||||||
|
allowAuthenticated: false
|
|
@ -274,6 +274,18 @@ const appRoutes: Routes = [
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'tenant-configuration',
|
||||||
|
loadChildren: () => import('./ui/admin/tenant-configuration/tenant-configuration.module').then(m => m.TenantConfigurationModule),
|
||||||
|
data: {
|
||||||
|
authContext: {
|
||||||
|
permissions: [AppPermission.ViewTenantConfigurationPage]
|
||||||
|
},
|
||||||
|
...BreadcrumbService.generateRouteDataConfiguration({
|
||||||
|
title: 'BREADCRUMBS.TENANT-CONFIGURATION'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'notifications',
|
path: 'notifications',
|
||||||
loadChildren: () => import('@notification-service/ui/admin/notification/notification.module').then(m => m.NotificationModule),
|
loadChildren: () => import('@notification-service/ui/admin/notification/notification.module').then(m => m.NotificationModule),
|
||||||
|
|
|
@ -1,75 +1,199 @@
|
||||||
export enum AppPermission {
|
export enum AppPermission {
|
||||||
//DescriptionTemplateType
|
/////
|
||||||
BrowseDescriptionTemplateType = "BrowseDescriptionTemplateType",
|
DeferredAffiliation = "DeferredAffiliation",
|
||||||
EditDescriptionTemplateType = "EditDescriptionTemplateType",
|
|
||||||
DeleteDescriptionTemplateType = "DeleteDescriptionTemplateType",
|
|
||||||
|
|
||||||
//DmpBlueprint
|
//Public
|
||||||
BrowseDmpBlueprint = "BrowseDmpBlueprint",
|
PublicBrowseDescription = "PublicBrowseDescription",
|
||||||
EditDmpBlueprint = "EditDmpBlueprint",
|
PublicBrowseDescriptionTemplate = "PublicBrowseDescriptionTemplate",
|
||||||
DeleteDmpBlueprint = "DeleteDmpBlueprint",
|
PublicBrowseDmp = "PublicBrowseDmp",
|
||||||
|
PublicBrowseDmpReference = "PublicBrowseDmpReference",
|
||||||
//Description
|
PublicBrowseDmpUser = "PublicBrowseDmpUser",
|
||||||
BrowseDescription = "BrowseDescription",
|
PublicBrowseReference = "PublicBrowseReference",
|
||||||
EditDescription = "EditDescription",
|
PublicBrowseUser = "PublicBrowseUser",
|
||||||
FinalizeDescription = "FinalizeDescription",
|
PublicBrowseDashboardStatistics = "PublicBrowseDashboardStatistics",
|
||||||
DeleteDescription= "DeleteDescription",
|
PublicSendContactSupport = "PublicSendContactSupport",
|
||||||
|
PublicBrowseReferenceType = "PublicBrowseReferenceType",
|
||||||
//Dmp
|
//Elastic
|
||||||
BrowseDmp = "BrowseDmp",
|
ManageElastic = "ManageElastic",
|
||||||
EditDmp = "EditDmp",
|
//Queue Events
|
||||||
NewDmp = "NewDmp",
|
ManageQueueEvents = "ManageQueueEvents",
|
||||||
DeleteDmp = "DeleteDmp",
|
|
||||||
DepositDmp = "DepositDmp",
|
|
||||||
CloneDmp = "CloneDmp",
|
|
||||||
CreateNewVersionDmp = "CreateNewVersionDmp",
|
|
||||||
ExportDmp = "ExportDmp",
|
|
||||||
FinalizeDmp = "FinalizeDmp",
|
|
||||||
AssignDmpUsers = "AssignDmpUsers",
|
|
||||||
InviteDmpUsers = "InviteDmpUsers",
|
|
||||||
|
|
||||||
//DescriptionTemplateType
|
|
||||||
BrowseDescriptionTemplate = "BrowseDescriptionTemplate",
|
|
||||||
EditDescriptionTemplate = "EditDescriptionTemplate",
|
|
||||||
DeleteDescriptionTemplate = "DeleteDescriptionTemplate",
|
|
||||||
|
|
||||||
|
|
||||||
//ReferenceType
|
//Deposit
|
||||||
BrowseReferenceType = "BrowseReferenceType",
|
BrowseDeposit = "BrowseDeposit",
|
||||||
EditReferenceType = "EditReferenceType",
|
EditDeposit = "BrowseDeposit",
|
||||||
DeleteReferenceType = "DeleteReferenceType",
|
|
||||||
|
|
||||||
//Tenant
|
|
||||||
BrowseTenant = "BrowseTenant",
|
|
||||||
EditTenant = "EditTenant",
|
|
||||||
DeleteTenant = "DeleteTenant",
|
|
||||||
|
|
||||||
//User
|
|
||||||
BrowseUser = "BrowseUser",
|
|
||||||
EditUser = "EditUser",
|
|
||||||
DeleteUser = "DeleteUser",
|
|
||||||
ExportUsers = "ExportUsers",
|
|
||||||
|
|
||||||
//Reference
|
|
||||||
BrowseReference = "BrowseReference",
|
|
||||||
EditReference = "EditReference",
|
|
||||||
DeleteReference = "DeleteReference",
|
|
||||||
|
|
||||||
//Language
|
//Language
|
||||||
BrowseLanguage = "BrowseLanguage",
|
BrowseLanguage = "BrowseLanguage",
|
||||||
EditLanguage = "EditLanguage",
|
EditLanguage = "EditLanguage",
|
||||||
DeleteLanguage = "DeleteLanguage",
|
DeleteLanguage = "DeleteLanguage",
|
||||||
|
|
||||||
//Notification Template
|
|
||||||
|
//NotificationTemplate
|
||||||
BrowseNotificationTemplate = "BrowseNotificationTemplate",
|
BrowseNotificationTemplate = "BrowseNotificationTemplate",
|
||||||
EditNotificationTemplate = "EditNotificationTemplate",
|
EditNotificationTemplate = "EditNotificationTemplate",
|
||||||
DeleteNotificationTemplate = "DeleteNotificationTemplate",
|
DeleteNotificationTemplate = "DeleteNotificationTemplate",
|
||||||
|
|
||||||
//Prefilling Source
|
//Language
|
||||||
BrowsePrefillingSource= "BrowsePrefillingSource",
|
BrowseStatistics = "BrowseStatistics",
|
||||||
EditPrefillingSource = "EditPrefillingSource",
|
BrowsePublicStatistics = "BrowsePublicStatistics",
|
||||||
|
|
||||||
|
//DescriptionTemplate
|
||||||
|
BrowseDescriptionTemplate = "BrowseDescriptionTemplate",
|
||||||
|
EditDescriptionTemplate = "EditDescriptionTemplate",
|
||||||
|
DeleteDescriptionTemplate = "DeleteDescriptionTemplate",
|
||||||
|
CloneDescriptionTemplate = "CloneDescriptionTemplate",
|
||||||
|
CreateNewVersionDescriptionTemplate = "CreateNewVersionDescriptionTemplate",
|
||||||
|
ImportDescriptionTemplate = "ImportDescriptionTemplate",
|
||||||
|
ExportDescriptionTemplate = "ExportDescriptionTemplate",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//User
|
||||||
|
BrowseUser = "BrowseUser",
|
||||||
|
EditUser = "EditUser",
|
||||||
|
DeleteUser = "DeleteUser",
|
||||||
|
ExportUsers = "ExportUsers",
|
||||||
|
BrowseDmpAssociatedUser = "BrowseDmpAssociatedUser",
|
||||||
|
|
||||||
|
|
||||||
|
//StorageFile
|
||||||
|
BrowseStorageFile = "BrowseStorageFile",
|
||||||
|
EditStorageFile = "EditStorageFile",
|
||||||
|
DeleteStorageFile = "DeleteStorageFile",
|
||||||
|
|
||||||
|
//DescriptionTemplateType
|
||||||
|
BrowseDescriptionTemplateType = "BrowseDescriptionTemplateType",
|
||||||
|
EditDescriptionTemplateType = "EditDescriptionTemplateType",
|
||||||
|
DeleteDescriptionTemplateType = "DeleteDescriptionTemplateType",
|
||||||
|
|
||||||
|
//Dmp
|
||||||
|
BrowseDmp = "BrowseDmp",
|
||||||
|
EditDmp = "EditDmp",
|
||||||
|
NewDmp = "NewDmp",
|
||||||
|
DepositDmp = "DepositDmp",
|
||||||
|
DeleteDmp = "DeleteDmp",
|
||||||
|
CloneDmp = "CloneDmp",
|
||||||
|
ExportDmp = "ExportDmp",
|
||||||
|
CreateNewVersionDmp = "CreateNewVersionDmp",
|
||||||
|
FinalizeDmp = "FinalizeDmp",
|
||||||
|
UndoFinalizeDmp = "UndoFinalizeDmp",
|
||||||
|
AssignDmpUsers = "AssignDmpUsers",
|
||||||
|
InviteDmpUsers = "InviteDmpUsers",
|
||||||
|
|
||||||
|
//DmpBlueprint
|
||||||
|
BrowseDmpBlueprint = "BrowseDmpBlueprint",
|
||||||
|
EditDmpBlueprint = "EditDmpBlueprint",
|
||||||
|
DeleteDmpBlueprint = "DeleteDmpBlueprint",
|
||||||
|
CloneDmpBlueprint = "CloneDmpBlueprint",
|
||||||
|
CreateNewVersionDmpBlueprint = "CreateNewVersionDmpBlueprint",
|
||||||
|
ExportDmpBlueprint = "ExportDmpBlueprint",
|
||||||
|
ImportDmpBlueprint = "ImportDmpBlueprint",
|
||||||
|
|
||||||
|
//DmpDescriptionTemplate
|
||||||
|
BrowseDmpDescriptionTemplate = "BrowseDmpDescriptionTemplate",
|
||||||
|
EditDmpDescriptionTemplate = "EditDmpDescriptionTemplate",
|
||||||
|
DeleteDmpDescriptionTemplate = "DeleteDmpDescriptionTemplate",
|
||||||
|
|
||||||
|
//DmpUser
|
||||||
|
BrowseDmpUser = "BrowseDmpUser",
|
||||||
|
EditDmpUser = "EditDmpUser",
|
||||||
|
DeleteDmpUser = "DeleteDmpUser",
|
||||||
|
|
||||||
|
//Description
|
||||||
|
BrowseDescription = "BrowseDescription",
|
||||||
|
EditDescription = "EditDescription",
|
||||||
|
FinalizeDescription = "FinalizeDescription",
|
||||||
|
DeleteDescription = "DeleteDescription",
|
||||||
|
CloneDescription = "CloneDescription",
|
||||||
|
|
||||||
|
//DescriptionTag
|
||||||
|
BrowseDescriptionTag = "BrowseDescriptionTag",
|
||||||
|
EditDescriptionTag = "EditDescriptionTag",
|
||||||
|
DeleteDescriptionTag = "DeleteDescriptionTag",
|
||||||
|
|
||||||
|
//DescriptionTemplateType
|
||||||
|
BrowseEntityDoi = "BrowseEntityDoi",
|
||||||
|
EditEntityDoi = "EditEntityDoi",
|
||||||
|
DeleteEntityDoi = "DeleteEntityDoi",
|
||||||
|
|
||||||
|
//UserSettings
|
||||||
|
BrowseUserSettings = "BrowseUserSettings",
|
||||||
|
EditUserSettings = "EditUserSettings",
|
||||||
|
DeleteUserSettings = "DeleteUserSettings",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Reference
|
||||||
|
BrowseReference = "BrowseReference",
|
||||||
|
EditReference = "EditReference",
|
||||||
|
DeleteReference = "DeleteReference",
|
||||||
|
|
||||||
|
//Tag
|
||||||
|
BrowseTag = "BrowseTag",
|
||||||
|
EditTag = "EditTag",
|
||||||
|
DeleteTag = "DeleteTag",
|
||||||
|
|
||||||
|
//DmpReference
|
||||||
|
BrowseDmpReference = "BrowseDmpReference",
|
||||||
|
EditDmpReference = "EditDmpReference",
|
||||||
|
DeleteDmpReference = "DeleteDmpReference",
|
||||||
|
|
||||||
|
//DescriptionReference
|
||||||
|
BrowseDescriptionReference = "BrowseDescriptionReference",
|
||||||
|
EditDescriptionReference = "EditDescriptionReference",
|
||||||
|
DeleteDescriptionReference = "DeleteDescriptionReference",
|
||||||
|
|
||||||
|
//SupportiveMaterial
|
||||||
|
BrowseSupportiveMaterial = "BrowseSupportiveMaterial",
|
||||||
|
EditSupportiveMaterial= "EditSupportiveMaterial",
|
||||||
|
DeleteSupportiveMaterial = "DeleteSupportiveMaterial",
|
||||||
|
|
||||||
|
//ReferenceType
|
||||||
|
BrowseReferenceType = "BrowseReferenceType",
|
||||||
|
EditReferenceType= "EditReferenceType",
|
||||||
|
DeleteReferenceType = "DeleteReferenceType",
|
||||||
|
|
||||||
|
//Tenant
|
||||||
|
BrowseTenant = "BrowseTenant",
|
||||||
|
EditTenant= "EditTenant",
|
||||||
|
DeleteTenant = "DeleteTenant",
|
||||||
|
AllowNoTenant = "AllowNoTenant",
|
||||||
|
|
||||||
|
//TenantConfiguration
|
||||||
|
BrowseTenantConfiguration = "BrowseTenantConfiguration",
|
||||||
|
EditTenantConfiguration = "EditTenantConfiguration",
|
||||||
|
DeleteTenantConfiguration = "DeleteTenantConfiguration",
|
||||||
|
|
||||||
|
//TenantUser
|
||||||
|
BrowseTenantUser = "BrowseTenantUser",
|
||||||
|
EditTenantUser = "EditTenantUser",
|
||||||
|
DeleteTenantUser = "DeleteTenantUser",
|
||||||
|
|
||||||
|
//Prefilling
|
||||||
|
BrowsePrefilling = "BrowsePrefilling",
|
||||||
|
|
||||||
|
|
||||||
|
//Lock
|
||||||
|
BrowseLock = "BrowseLock",
|
||||||
|
EditLock = "EditLock",
|
||||||
|
DeleteLock = "DeleteLock",
|
||||||
|
|
||||||
|
//ContactSupport
|
||||||
|
SendContactSupport = "SendContactSupport",
|
||||||
|
|
||||||
|
//ActionConfirmation
|
||||||
|
BrowseActionConfirmation = "BrowseActionConfirmation",
|
||||||
|
EditActionConfirmation = "EditActionConfirmation",
|
||||||
|
DeleteActionConfirmation = "DeleteActionConfirmation",
|
||||||
|
|
||||||
|
//PrefillingSource
|
||||||
|
BrowsePrefillingSource = "BrowsePrefillingSource",
|
||||||
|
EditPrefillingSource= "EditPrefillingSource",
|
||||||
DeletePrefillingSource = "DeletePrefillingSource",
|
DeletePrefillingSource = "DeletePrefillingSource",
|
||||||
|
|
||||||
|
|
||||||
// UI Pages
|
// UI Pages
|
||||||
ViewDescriptionTemplateTypePage = "ViewDescriptionTemplateTypePage",
|
ViewDescriptionTemplateTypePage = "ViewDescriptionTemplateTypePage",
|
||||||
ViewMaintenancePage = "ViewMaintenancePage",
|
ViewMaintenancePage = "ViewMaintenancePage",
|
||||||
|
@ -91,5 +215,6 @@ export enum AppPermission {
|
||||||
ViewMyDmpPage = "ViewMyDmpPage",
|
ViewMyDmpPage = "ViewMyDmpPage",
|
||||||
ViewHomePage = "ViewHomePage",
|
ViewHomePage = "ViewHomePage",
|
||||||
ViewMineInAppNotificationPage = "ViewMineInAppNotificationPage",
|
ViewMineInAppNotificationPage = "ViewMineInAppNotificationPage",
|
||||||
|
ViewTenantConfigurationPage = "ViewTenantConfigurationPage",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,5 +13,8 @@ export enum ResponseErrorCode {
|
||||||
DmpBlueprintHasNoDescriptionTemplates = 120,
|
DmpBlueprintHasNoDescriptionTemplates = 120,
|
||||||
DmpBlueprintNewVersionConflict = 121,
|
DmpBlueprintNewVersionConflict = 121,
|
||||||
DmpDescriptionTemplateCanNotRemove = 122,
|
DmpDescriptionTemplateCanNotRemove = 122,
|
||||||
TenantTampering = 123
|
TenantTampering = 123,
|
||||||
|
TenantConfigurationTypeCanNotChange = 124,
|
||||||
|
MultipleTenantConfigurationTypeNotAllowed = 125,
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
export enum TenantConfigurationType {
|
||||||
|
DepositPlugins = 0,
|
||||||
|
FileTransformerPlugins = 1,
|
||||||
|
DefaultUserLocale = 2,
|
||||||
|
Logo = 3,
|
||||||
|
CssColors = 4,
|
||||||
|
}
|
|
@ -46,6 +46,7 @@ import { SemanticsService } from './services/semantic/semantics.service';
|
||||||
import { PrefillingSourceService } from './services/prefilling-source/prefilling-source.service';
|
import { PrefillingSourceService } from './services/prefilling-source/prefilling-source.service';
|
||||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||||
import { StorageFileService } from './services/storage-file/storage-file.service';
|
import { StorageFileService } from './services/storage-file/storage-file.service';
|
||||||
|
import { TenantConfigurationService } from './services/tenant-configuration/tenant-configuration.service';
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// This is shared module that provides all the services. Its imported only once on the AppModule.
|
// This is shared module that provides all the services. Its imported only once on the AppModule.
|
||||||
|
@ -110,6 +111,7 @@ export class CoreServiceModule {
|
||||||
SemanticsService,
|
SemanticsService,
|
||||||
PrefillingSourceService,
|
PrefillingSourceService,
|
||||||
VisibilityRulesService,
|
VisibilityRulesService,
|
||||||
|
TenantConfigurationService,
|
||||||
StorageFileService
|
StorageFileService
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
import { TenantConfigurationType } from "@app/core/common/enum/tenant-configuration-type";
|
||||||
|
import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model";
|
||||||
|
import { StorageFile } from "../storage-file/storage-file";
|
||||||
|
import { Guid } from "@common/types/guid";
|
||||||
|
|
||||||
|
export interface TenantConfiguration extends BaseEntity{
|
||||||
|
type?: TenantConfigurationType;
|
||||||
|
cssColors?: CssColorsTenantConfiguration;
|
||||||
|
defaultUserLocale?: DefaultUserLocaleTenantConfiguration;
|
||||||
|
depositPlugins?: DepositTenantConfiguration;
|
||||||
|
fileTransformerPlugins?: FileTransformerTenantConfiguration;
|
||||||
|
logo?: LogoTenantConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CssColorsTenantConfiguration{
|
||||||
|
primaryColor: string;
|
||||||
|
primaryColor2: string;
|
||||||
|
primaryColor3: string;
|
||||||
|
secondaryColor: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DefaultUserLocaleTenantConfiguration{
|
||||||
|
timezone: string;
|
||||||
|
language: string;
|
||||||
|
culture: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DepositTenantConfiguration{
|
||||||
|
sources: DepositSource[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileTransformerTenantConfiguration{
|
||||||
|
sources: FileTransformerSource[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DepositSource{
|
||||||
|
repositoryId: string;
|
||||||
|
url: string;
|
||||||
|
issuerUrl: string;
|
||||||
|
clientId: string;
|
||||||
|
clientSecret: string;
|
||||||
|
scope: string;
|
||||||
|
pdfTransformerId: string;
|
||||||
|
rdaTransformerId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileTransformerSource{
|
||||||
|
transformerId: string;
|
||||||
|
url: string;
|
||||||
|
issuerUrl: string;
|
||||||
|
clientId: string;
|
||||||
|
clientSecret: string;
|
||||||
|
scope: string;
|
||||||
|
}
|
||||||
|
export interface LogoTenantConfiguration{
|
||||||
|
storageFile: StorageFile;
|
||||||
|
}
|
||||||
|
//persist
|
||||||
|
|
||||||
|
export interface TenantConfigurationPersist extends BaseEntityPersist{
|
||||||
|
type: TenantConfigurationType;
|
||||||
|
cssColors?: CssColorsTenantConfigurationPersist;
|
||||||
|
defaultUserLocale?: DefaultUserLocaleTenantConfigurationPersist;
|
||||||
|
depositPlugins?: DepositTenantConfigurationPersist;
|
||||||
|
fileTransformerPlugins?: FileTransformerTenantConfigurationPersist;
|
||||||
|
logo?: LogoTenantConfigurationPersist;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CssColorsTenantConfigurationPersist{
|
||||||
|
primaryColor: string;
|
||||||
|
primaryColor2: string;
|
||||||
|
primaryColor3: string;
|
||||||
|
secondaryColor: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DefaultUserLocaleTenantConfigurationPersist{
|
||||||
|
timezone: string;
|
||||||
|
language: string;
|
||||||
|
culture: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DepositTenantConfigurationPersist{
|
||||||
|
sources: DepositSourcePersist[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileTransformerTenantConfigurationPersist{
|
||||||
|
sources: FileTransformerSourcePersist[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DepositSourcePersist{
|
||||||
|
repositoryId: string;
|
||||||
|
url: string;
|
||||||
|
issuerUrl: string;
|
||||||
|
clientId: string;
|
||||||
|
clientSecret: string;
|
||||||
|
scope: string;
|
||||||
|
pdfTransformerId: string;
|
||||||
|
rdaTransformerId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileTransformerSourcePersist{
|
||||||
|
transformerId: string;
|
||||||
|
url: string;
|
||||||
|
issuerUrl: string;
|
||||||
|
clientId: string;
|
||||||
|
clientSecret: string;
|
||||||
|
scope: string;
|
||||||
|
}
|
||||||
|
export interface LogoTenantConfigurationPersist{
|
||||||
|
storageFileId: Guid;
|
||||||
|
}
|
|
@ -4,33 +4,6 @@ export interface Tenant extends BaseEntity{
|
||||||
name?: string;
|
name?: string;
|
||||||
code?: string;
|
code?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
config?: TenantConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TenantConfig{
|
|
||||||
deposit: TenantDepositConfig;
|
|
||||||
fileTransformers: TenantFileTransformersConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TenantDepositConfig{
|
|
||||||
sources: TenantSource[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TenantFileTransformersConfig{
|
|
||||||
sources: TenantSource[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TenantSource{
|
|
||||||
url: string;
|
|
||||||
codes: string[];
|
|
||||||
issuerUrl: string;
|
|
||||||
clientId: string;
|
|
||||||
clientSecret: string;
|
|
||||||
scope: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SourceCode{
|
|
||||||
code: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//persist
|
//persist
|
||||||
|
@ -39,31 +12,5 @@ export interface TenantPersist extends BaseEntityPersist{
|
||||||
name: string;
|
name: string;
|
||||||
code: string;
|
code: string;
|
||||||
description: string;
|
description: string;
|
||||||
config?: TenantConfigPersist;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TenantConfigPersist{
|
|
||||||
deposit: TenantDepositConfigPersist;
|
|
||||||
fileTransformers: TenantFileTransformersConfigPersist;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TenantDepositConfigPersist{
|
|
||||||
sources: TenantSourcePersist[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TenantFileTransformersConfigPersist{
|
|
||||||
sources: TenantSourcePersist[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TenantSourcePersist{
|
|
||||||
url: string;
|
|
||||||
codes: string[];
|
|
||||||
issuerUrl: string;
|
|
||||||
clientId: string;
|
|
||||||
clientSecret: string;
|
|
||||||
scope: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SourceCodePersist{
|
|
||||||
code: string;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { Lookup } from '@common/model/lookup';
|
||||||
|
import { Guid } from '@common/types/guid';
|
||||||
|
import { IsActive } from '../common/enum/is-active.enum';
|
||||||
|
import { TenantConfigurationType } from '../common/enum/tenant-configuration-type';
|
||||||
|
|
||||||
|
export class TenantConfigurationLookup extends Lookup implements TenantConfigurationFilter {
|
||||||
|
ids: Guid[];
|
||||||
|
excludedIds: Guid[];
|
||||||
|
types: TenantConfigurationType[];
|
||||||
|
isActive: IsActive[];
|
||||||
|
tenantIds: Guid[];
|
||||||
|
tenantIsSet: boolean;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TenantConfigurationFilter {
|
||||||
|
ids: Guid[];
|
||||||
|
excludedIds: Guid[];
|
||||||
|
types: TenantConfigurationType[];
|
||||||
|
tenantIds: Guid[];
|
||||||
|
tenantIsSet: boolean;
|
||||||
|
isActive: IsActive[];
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { QueryResult } from '@common/model/query-result';
|
||||||
|
import { FilterService } from '@common/modules/text-filter/filter-service';
|
||||||
|
import { Guid } from '@common/types/guid';
|
||||||
|
import { Observable, throwError } from 'rxjs';
|
||||||
|
import { catchError } from 'rxjs/operators';
|
||||||
|
import { ConfigurationService } from '../configuration/configuration.service';
|
||||||
|
import { BaseHttpV2Service } from '../http/base-http-v2.service';
|
||||||
|
import { TenantConfigurationLookup } from '@app/core/query/tenant-configuration.lookup';
|
||||||
|
import { TenantConfiguration, TenantConfigurationPersist } from '@app/core/model/tenant-configuaration/tenant-configuration';
|
||||||
|
import { TenantConfigurationType } from '@app/core/common/enum/tenant-configuration-type';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TenantConfigurationService {
|
||||||
|
|
||||||
|
constructor(private http: BaseHttpV2Service, private configurationService: ConfigurationService, private filterService: FilterService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private get apiBase(): string { return `${this.configurationService.server}tenant-configuration`; }
|
||||||
|
|
||||||
|
query(q: TenantConfigurationLookup): Observable<QueryResult<TenantConfiguration>> {
|
||||||
|
const url = `${this.apiBase}/query`;
|
||||||
|
return this.http.post<QueryResult<TenantConfiguration>>(url, q).pipe(catchError((error: any) => throwError(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
getSingle(id: Guid, reqFields: string[] = []): Observable<TenantConfiguration> {
|
||||||
|
const url = `${this.apiBase}/${id}`;
|
||||||
|
const options = { params: { f: reqFields } };
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.get<TenantConfiguration>(url, options).pipe(
|
||||||
|
catchError((error: any) => throwError(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentTenantType(type: TenantConfigurationType, reqFields: string[] = []): Observable<TenantConfiguration> {
|
||||||
|
const url = `${this.apiBase}/current-tenant/${type}`;
|
||||||
|
const options = { params: { f: reqFields } };
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.get<TenantConfiguration>(url, options).pipe(
|
||||||
|
catchError((error: any) => throwError(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
persist(item: TenantConfigurationPersist): Observable<TenantConfiguration> {
|
||||||
|
const url = `${this.apiBase}/persist`;
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.post<TenantConfiguration>(url, item).pipe(
|
||||||
|
catchError((error: any) => throwError(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(id: Guid): Observable<void> {
|
||||||
|
const url = `${this.apiBase}/${id}`;
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.delete<void>(url).pipe(
|
||||||
|
catchError((error: any) => throwError(error)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
<div *ngIf="formGroup" class="container-fluid css-colors">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<mat-form-field class="w-100">
|
||||||
|
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.PRIMARY-COLOR' | translate}}</mat-label>
|
||||||
|
<input matInput type="text" name="primaryColor" [formControl]="formGroup.get('cssColors')?.get('primaryColor')" required>
|
||||||
|
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor')?.hasError('backendError')">{{formGroup.get('cssColors')?.get('primaryColor')?.getError('backendError').message}}</mat-error>
|
||||||
|
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor')?.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="w-100">
|
||||||
|
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.PRIMARY-COLOR-2' | translate}}</mat-label>
|
||||||
|
<input matInput type="text" name="primaryColor2" [formControl]="formGroup.get('cssColors')?.get('primaryColor2')" required>
|
||||||
|
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor2')?.hasError('backendError')">{{formGroup.get('cssColors')?.get('primaryColor2')?.getError('backendError').message}}</mat-error>
|
||||||
|
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor2')?.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="w-100">
|
||||||
|
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.PRIMARY-COLOR-3' | translate}}</mat-label>
|
||||||
|
<input matInput type="text" name="primaryColor3" [formControl]="formGroup.get('cssColors')?.get('primaryColor3')" required>
|
||||||
|
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor3')?.hasError('backendError')">{{formGroup.get('cssColors')?.get('primaryColor3')?.getError('backendError').message}}</mat-error>
|
||||||
|
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor3')?.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="w-100">
|
||||||
|
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.SECONDARY-COLOR' | translate}}</mat-label>
|
||||||
|
<input matInput type="text" name="secondaryColor" [formControl]="formGroup.get('cssColors')?.get('secondaryColor')" required>
|
||||||
|
<mat-error *ngIf="formGroup.get('cssColors')?.get('secondaryColor')?.hasError('backendError')">{{formGroup.get('cssColors')?.get('secondaryColor')?.getError('backendError').message}}</mat-error>
|
||||||
|
<mat-error *ngIf="formGroup.get('cssColors')?.get('secondaryColor')?.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="row actions-row">
|
||||||
|
<div class="col"></div>
|
||||||
|
<div class="col-auto" *ngIf="editorModel.id"><button mat-raised-button color="primary" (click)="delete()">
|
||||||
|
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.RESET-TO-DEFAULT' | translate}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto"><button mat-raised-button color="primary" (click)="formSubmit()">
|
||||||
|
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.SAVE' | translate}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,3 @@
|
||||||
|
.css-colors {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,207 @@
|
||||||
|
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { UntypedFormGroup } from '@angular/forms';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
|
||||||
|
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||||
|
import { AuthService } from '@app/core/services/auth/auth.service';
|
||||||
|
import { MatomoService } from '@app/core/services/matomo/matomo-service';
|
||||||
|
import { FormService } from '@common/forms/form-service';
|
||||||
|
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
|
||||||
|
import { HttpError, HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { map, takeUntil } from 'rxjs/operators';
|
||||||
|
import { TenantConfigurationEditorModel } from './css-colors-editor.model';
|
||||||
|
import { TenantConfiguration, TenantConfigurationPersist } from '@app/core/model/tenant-configuaration/tenant-configuration';
|
||||||
|
import { TenantConfigurationService } from '@app/core/services/tenant-configuration/tenant-configuration.service';
|
||||||
|
import { CssColorsEditorService } from './css-colors-editor.service';
|
||||||
|
import { CssColorsEditorResolver } from './css-colors-editor.resolver';
|
||||||
|
import { BasePendingChangesComponent } from '@common/base/base-pending-changes.component';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { TenantConfigurationType } from '@app/core/common/enum/tenant-configuration-type';
|
||||||
|
import { HttpErrorResponse } from '@angular/common/http';
|
||||||
|
import { ResponseErrorCode } from '@app/core/common/enum/respone-error-code';
|
||||||
|
import { LoggingService } from '@app/core/services/logging/logging-service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-tenant-configuration-css-colors-editor',
|
||||||
|
templateUrl: 'css-colors-editor.component.html',
|
||||||
|
styleUrls: ['./css-colors-editor.component.scss'],
|
||||||
|
providers: [CssColorsEditorService]
|
||||||
|
})
|
||||||
|
export class CssColorsEditorComponent extends BasePendingChangesComponent implements OnInit {
|
||||||
|
|
||||||
|
isNew = true;
|
||||||
|
formGroup: UntypedFormGroup = null;
|
||||||
|
|
||||||
|
get editorModel(): TenantConfigurationEditorModel { return this._editorModel; }
|
||||||
|
set editorModel(value: TenantConfigurationEditorModel) { this._editorModel = value; }
|
||||||
|
private _editorModel: TenantConfigurationEditorModel;
|
||||||
|
|
||||||
|
protected get canDelete(): boolean {
|
||||||
|
return !this.isNew && this.hasPermission(this.authService.permissionEnum.DeleteTenantConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected get canSave(): boolean {
|
||||||
|
return this.hasPermission(this.authService.permissionEnum.EditTenantConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasPermission(permission: AppPermission): boolean {
|
||||||
|
return this.authService.hasPermission(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected dialog: MatDialog,
|
||||||
|
protected language: TranslateService,
|
||||||
|
protected formService: FormService,
|
||||||
|
protected uiNotificationService: UiNotificationService,
|
||||||
|
protected httpErrorHandlingService: HttpErrorHandlingService,
|
||||||
|
protected authService: AuthService,
|
||||||
|
private logger: LoggingService,
|
||||||
|
private tenantConfigurationService: TenantConfigurationService,
|
||||||
|
private cssColorsEditorService: CssColorsEditorService,
|
||||||
|
private matomoService: MatomoService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
canDeactivate(): boolean | Observable<boolean> {
|
||||||
|
return this.formGroup ? !this.formGroup.dirty : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.matomoService.trackPageView('Admin: TenantConfigurations');
|
||||||
|
this.getItem((entity) => {
|
||||||
|
this.prepareForm(entity);
|
||||||
|
if (this.formGroup && this.editorModel.belongsToCurrentTenant == false) {
|
||||||
|
this.formGroup.disable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getItem(successFunction: (item: TenantConfiguration) => void) {
|
||||||
|
this.tenantConfigurationService.getCurrentTenantType(TenantConfigurationType.CssColors, CssColorsEditorResolver.lookupFields())
|
||||||
|
.pipe(map(data => data as TenantConfiguration), takeUntil(this._destroyed))
|
||||||
|
.subscribe(
|
||||||
|
data => successFunction(data),
|
||||||
|
error => this.onCallbackError(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCallbackError(errorResponse: HttpErrorResponse) {
|
||||||
|
|
||||||
|
console.log("Error:", errorResponse);
|
||||||
|
|
||||||
|
const error: HttpError = this.httpErrorHandlingService.getError(errorResponse);
|
||||||
|
if (error.statusCode === 400) {
|
||||||
|
this.editorModel.validationErrorModel.fromJSONObject(errorResponse.error);
|
||||||
|
if(errorResponse.error.code === ResponseErrorCode.TenantConfigurationTypeCanNotChange){
|
||||||
|
this.uiNotificationService.snackBarNotification(errorResponse.error.error, SnackBarNotificationLevel.Error);
|
||||||
|
}
|
||||||
|
if(errorResponse.error.code === ResponseErrorCode.MultipleTenantConfigurationTypeNotAllowed){
|
||||||
|
this.uiNotificationService.snackBarNotification(errorResponse.error.error, SnackBarNotificationLevel.Error);
|
||||||
|
}
|
||||||
|
this.formService.validateAllFormFields(this.formGroup);
|
||||||
|
} else {
|
||||||
|
this.uiNotificationService.snackBarNotification(error.getMessagesString(), SnackBarNotificationLevel.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onCallbackSuccess(data?: any): void {
|
||||||
|
|
||||||
|
console.log("Success:", data);
|
||||||
|
|
||||||
|
this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
|
||||||
|
this.refreshData();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
prepareForm(data: TenantConfiguration) {
|
||||||
|
try {
|
||||||
|
this.editorModel = data ? new TenantConfigurationEditorModel().fromModel(data) : new TenantConfigurationEditorModel();
|
||||||
|
|
||||||
|
this.buildForm();
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('Could not parse TenantConfiguration item: ' + data + error);
|
||||||
|
this.uiNotificationService.snackBarNotification(this.language.instant('COMMONS.ERRORS.DEFAULT'), SnackBarNotificationLevel.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildForm() {
|
||||||
|
this.formGroup = this.editorModel.buildForm(null, !this.authService.hasPermission(AppPermission.EditTenantConfiguration));
|
||||||
|
this.cssColorsEditorService.setValidationErrorModel(this.editorModel.validationErrorModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshData(): void {
|
||||||
|
this.getItem((entity) => {
|
||||||
|
this.prepareForm(entity);
|
||||||
|
if (this.formGroup && this.editorModel.belongsToCurrentTenant == false) {
|
||||||
|
this.formGroup.disable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
persistEntity(onSuccess?: (response) => void): void {
|
||||||
|
const formData = this.formService.getValue(this.formGroup.value) as TenantConfigurationPersist;
|
||||||
|
|
||||||
|
this.tenantConfigurationService.persist(formData)
|
||||||
|
.pipe(takeUntil(this._destroyed)).subscribe(
|
||||||
|
complete => onSuccess ? onSuccess(complete) : this.onCallbackSuccess(complete),
|
||||||
|
error => this.onCallbackError(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
formSubmit(): void {
|
||||||
|
this.clearErrorModel();
|
||||||
|
this.formService.removeAllBackEndErrors(this.formGroup);
|
||||||
|
this.formService.touchAllFormFields(this.formGroup);
|
||||||
|
if (!this.isFormValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.persistEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public isFormValid() {
|
||||||
|
return this.formGroup.valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public delete() {
|
||||||
|
const value = this.formGroup.value;
|
||||||
|
if (value.id) {
|
||||||
|
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
||||||
|
maxWidth: '300px',
|
||||||
|
data: {
|
||||||
|
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'),
|
||||||
|
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
|
||||||
|
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
this.tenantConfigurationService.delete(value.id).pipe(takeUntil(this._destroyed))
|
||||||
|
.subscribe(
|
||||||
|
complete => this.onCallbackDeleteSuccessConfig(),
|
||||||
|
error => this.onCallbackError(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCallbackDeleteSuccessConfig(data?: any): void {
|
||||||
|
|
||||||
|
console.log("Success Delete:", data);
|
||||||
|
|
||||||
|
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DELETE'), SnackBarNotificationLevel.Success);
|
||||||
|
this.prepareForm(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
clearErrorModel() {
|
||||||
|
this.editorModel.validationErrorModel.clear();
|
||||||
|
this.formService.validateAllFormFields(this.formGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
|
||||||
|
import { TenantConfigurationType } from "@app/core/common/enum/tenant-configuration-type";
|
||||||
|
import { CssColorsTenantConfiguration, CssColorsTenantConfigurationPersist, TenantConfiguration, TenantConfigurationPersist } from "@app/core/model/tenant-configuaration/tenant-configuration";
|
||||||
|
import { BaseEditorModel } from "@common/base/base-form-editor-model";
|
||||||
|
import { BackendErrorValidator } from "@common/forms/validation/custom-validator";
|
||||||
|
import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model";
|
||||||
|
import { Validation, ValidationContext } from "@common/forms/validation/validation-context";
|
||||||
|
|
||||||
|
export class TenantConfigurationEditorModel extends BaseEditorModel implements TenantConfigurationPersist {
|
||||||
|
type: TenantConfigurationType;
|
||||||
|
cssColors: CssColorsTenantConfigurationEditorModel = new CssColorsTenantConfigurationEditorModel(this.validationErrorModel);
|
||||||
|
|
||||||
|
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
|
||||||
|
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||||
|
|
||||||
|
constructor() { super(); this.type = TenantConfigurationType.CssColors; }
|
||||||
|
|
||||||
|
public fromModel(item: TenantConfiguration): TenantConfigurationEditorModel {
|
||||||
|
if (item) {
|
||||||
|
super.fromModel(item);
|
||||||
|
this.type = item.type;
|
||||||
|
if (item.cssColors) this.cssColors = new CssColorsTenantConfigurationEditorModel(this.validationErrorModel).fromModel(item.cssColors);
|
||||||
|
} else {
|
||||||
|
this.type = TenantConfigurationType.CssColors;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup {
|
||||||
|
if (context == null) { context = this.createValidationContext(); }
|
||||||
|
|
||||||
|
return this.formBuilder.group({
|
||||||
|
id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
|
||||||
|
type: [{ value: this.type, disabled: disabled }, context.getValidation('type').validators],
|
||||||
|
hash: [{ value: this.hash, disabled: disabled }, context.getValidation('hash').validators],
|
||||||
|
cssColors: this.cssColors.buildForm({
|
||||||
|
rootPath: `cssColors.`,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createValidationContext(): ValidationContext {
|
||||||
|
const baseContext: ValidationContext = new ValidationContext();
|
||||||
|
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||||
|
baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] });
|
||||||
|
baseValidationArray.push({ key: 'type', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'type')] });
|
||||||
|
baseValidationArray.push({ key: 'hash', validators: [] });
|
||||||
|
|
||||||
|
baseContext.validation = baseValidationArray;
|
||||||
|
return baseContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CssColorsTenantConfigurationEditorModel implements CssColorsTenantConfigurationPersist {
|
||||||
|
primaryColor: string;
|
||||||
|
primaryColor2: string;
|
||||||
|
primaryColor3: string;
|
||||||
|
secondaryColor: string;
|
||||||
|
|
||||||
|
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||||
|
) { }
|
||||||
|
|
||||||
|
public fromModel(item: CssColorsTenantConfiguration): CssColorsTenantConfigurationEditorModel {
|
||||||
|
if (item) {
|
||||||
|
this.primaryColor = item.primaryColor;
|
||||||
|
this.primaryColor2 = item.primaryColor2;
|
||||||
|
this.primaryColor3 = item.primaryColor3;
|
||||||
|
this.secondaryColor = item.secondaryColor;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
buildForm(params?: {
|
||||||
|
context?: ValidationContext,
|
||||||
|
disabled?: boolean,
|
||||||
|
rootPath?: string
|
||||||
|
}): UntypedFormGroup {
|
||||||
|
let { context = null, disabled = false, rootPath } = params ?? {}
|
||||||
|
if (context == null) {
|
||||||
|
context = CssColorsTenantConfigurationEditorModel.createValidationContext({
|
||||||
|
validationErrorModel: this.validationErrorModel,
|
||||||
|
rootPath
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const form: UntypedFormGroup = this.formBuilder.group({
|
||||||
|
primaryColor: [{ value: this.primaryColor, disabled: disabled }, context.getValidation('primaryColor').validators],
|
||||||
|
primaryColor2: [{ value: this.primaryColor2, disabled: disabled }, context.getValidation('primaryColor2').validators],
|
||||||
|
primaryColor3: [{ value: this.primaryColor3, disabled: disabled }, context.getValidation('primaryColor3').validators],
|
||||||
|
secondaryColor: [{ value: this.secondaryColor, disabled: disabled }, context.getValidation('secondaryColor').validators],
|
||||||
|
});
|
||||||
|
|
||||||
|
return form;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static createValidationContext(params: {
|
||||||
|
rootPath?: string,
|
||||||
|
validationErrorModel: ValidationErrorModel
|
||||||
|
}): ValidationContext {
|
||||||
|
const { rootPath = '', validationErrorModel } = params;
|
||||||
|
|
||||||
|
const baseContext: ValidationContext = new ValidationContext();
|
||||||
|
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||||
|
baseValidationArray.push({ key: 'primaryColor', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}primaryColor`)] });
|
||||||
|
baseValidationArray.push({ key: 'primaryColor2', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}primaryColor2`)] });
|
||||||
|
baseValidationArray.push({ key: 'primaryColor3', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}primaryColor3`)] });
|
||||||
|
baseValidationArray.push({ key: 'secondaryColor', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}secondaryColor`)] });
|
||||||
|
|
||||||
|
baseContext.validation = baseValidationArray;
|
||||||
|
return baseContext;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { TenantConfigurationType } from '@app/core/common/enum/tenant-configuration-type';
|
||||||
|
import { CssColorsTenantConfiguration, TenantConfiguration } from '@app/core/model/tenant-configuaration/tenant-configuration';
|
||||||
|
import { TenantConfigurationService } from '@app/core/services/tenant-configuration/tenant-configuration.service';
|
||||||
|
import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
|
||||||
|
import { BaseEditorResolver } from '@common/base/base-editor.resolver';
|
||||||
|
import { takeUntil, tap } from 'rxjs/operators';
|
||||||
|
import { nameof } from 'ts-simple-nameof';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CssColorsEditorResolver extends BaseEditorResolver {
|
||||||
|
|
||||||
|
constructor(private tenantConfigurationService: TenantConfigurationService, private breadcrumbService: BreadcrumbService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static lookupFields(): string[] {
|
||||||
|
return [
|
||||||
|
...BaseEditorResolver.lookupFields(),
|
||||||
|
nameof<TenantConfiguration>(x => x.id),
|
||||||
|
nameof<TenantConfiguration>(x => x.type),
|
||||||
|
nameof<TenantConfiguration>(x => x.cssColors),
|
||||||
|
|
||||||
|
[nameof<TenantConfiguration>(x => x.cssColors), nameof<CssColorsTenantConfiguration>(x => x.primaryColor)].join('.'),
|
||||||
|
[nameof<TenantConfiguration>(x => x.cssColors), nameof<CssColorsTenantConfiguration>(x => x.primaryColor2)].join('.'),
|
||||||
|
[nameof<TenantConfiguration>(x => x.cssColors), nameof<CssColorsTenantConfiguration>(x => x.primaryColor3)].join('.'),
|
||||||
|
[nameof<TenantConfiguration>(x => x.cssColors), nameof<CssColorsTenantConfiguration>(x => x.secondaryColor)].join('.'),
|
||||||
|
|
||||||
|
|
||||||
|
nameof<TenantConfiguration>(x => x.createdAt),
|
||||||
|
nameof<TenantConfiguration>(x => x.updatedAt),
|
||||||
|
nameof<TenantConfiguration>(x => x.hash),
|
||||||
|
nameof<TenantConfiguration>(x => x.isActive)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve() {
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
...CssColorsEditorResolver.lookupFields()
|
||||||
|
];
|
||||||
|
|
||||||
|
return this.tenantConfigurationService.getCurrentTenantType(TenantConfigurationType.CssColors, fields).pipe(takeUntil(this._destroyed));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CssColorsEditorService {
|
||||||
|
private validationErrorModel: ValidationErrorModel;
|
||||||
|
|
||||||
|
public setValidationErrorModel(validationErrorModel: ValidationErrorModel): void {
|
||||||
|
this.validationErrorModel = validationErrorModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getValidationErrorModel(): ValidationErrorModel {
|
||||||
|
return this.validationErrorModel;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
<div *ngIf="formGroup" class="container-fluid default-user-locale">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<mat-form-field class="w-100">
|
||||||
|
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.TIMEZONE' | translate}}</mat-label>
|
||||||
|
<mat-select [formControl]="this.formGroup.get('defaultUserLocale')?.get('timezone')" name="culture">
|
||||||
|
<mat-option *ngFor="let timezone of timezones" [value]="timezone">
|
||||||
|
{{ timezone | timezoneInfoDisplay }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="formGroup.get('defaultUserLocale')?.get('timezone').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
|
<mat-error *ngIf="formGroup.get('defaultUserLocale')?.get('timezone')?.hasError('backendError')">{{formGroup.get('defaultUserLocale')?.get('timezone')?.getError('backendError').message}}</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="w-100">
|
||||||
|
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.CULTURE' | translate}}</mat-label>
|
||||||
|
<mat-select [formControl]="this.formGroup.get('defaultUserLocale')?.get('culture')" name="culture">
|
||||||
|
<mat-option *ngFor="let culture of cultures" [value]="culture.name">
|
||||||
|
{{ culture.displayName }} - {{ culture.nativeName }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="formGroup.get('defaultUserLocale')?.get('culture').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
|
<mat-error *ngIf="formGroup.get('defaultUserLocale')?.get('culture')?.hasError('backendError')">{{formGroup.get('defaultUserLocale')?.get('culture')?.getError('backendError').message}}</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="w-100">
|
||||||
|
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.LANGUAGE' | translate}}</mat-label>
|
||||||
|
<mat-select [formControl]="this.formGroup.get('defaultUserLocale')?.get('language')" name="language">
|
||||||
|
<mat-option *ngFor="let language of languages" [value]="language">
|
||||||
|
{{ "GENERAL.LANGUAGES."+ language | translate }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="this.formGroup.get('defaultUserLocale')?.get('language')?.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
|
<mat-error *ngIf="formGroup.get('defaultUserLocale')?.get('language')?.hasError('backendError')">{{formGroup.get('defaultUserLocale')?.get('language')?.getError('backendError').message}}</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="row actions-row">
|
||||||
|
<div class="col"></div>
|
||||||
|
<div class="col-auto" *ngIf="editorModel.id"><button mat-raised-button color="primary" (click)="delete()">
|
||||||
|
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.RESET-TO-DEFAULT' | translate}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto"><button mat-raised-button color="primary" (click)="formSubmit()">
|
||||||
|
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.SAVE' | translate}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,2 @@
|
||||||
|
.default-user-locale {
|
||||||
|
}
|
|
@ -0,0 +1,229 @@
|
||||||
|
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { UntypedFormGroup } from '@angular/forms';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
|
||||||
|
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
|
||||||
|
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||||
|
import { AuthService } from '@app/core/services/auth/auth.service';
|
||||||
|
import { MatomoService } from '@app/core/services/matomo/matomo-service';
|
||||||
|
import { FormService } from '@common/forms/form-service';
|
||||||
|
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
|
||||||
|
import { HttpError, HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { map, takeUntil } from 'rxjs/operators';
|
||||||
|
import { TenantConfigurationEditorModel } from './default-user-locale-editor.model';
|
||||||
|
import { TenantConfiguration, TenantConfigurationPersist } from '@app/core/model/tenant-configuaration/tenant-configuration';
|
||||||
|
import { TenantConfigurationService } from '@app/core/services/tenant-configuration/tenant-configuration.service';
|
||||||
|
import { DefaultUserLocaleEditorService } from './default-user-locale-editor.service';
|
||||||
|
import { DefaultUserLocaleEditorResolver } from './default-user-locale-editor.resolver';
|
||||||
|
import { BasePendingChangesComponent } from '@common/base/base-pending-changes.component';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
import { TenantConfigurationType } from '@app/core/common/enum/tenant-configuration-type';
|
||||||
|
import { HttpErrorResponse } from '@angular/common/http';
|
||||||
|
import { ResponseErrorCode } from '@app/core/common/enum/respone-error-code';
|
||||||
|
import { LoggingService } from '@app/core/services/logging/logging-service';
|
||||||
|
import { CultureInfo } from '@app/core/model/culture-info';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
import { CultureService } from '@app/core/services/culture/culture-service';
|
||||||
|
import { LanguageService } from '@app/core/services/language/language.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-tenant-configuration-default-user-locale-editor',
|
||||||
|
templateUrl: 'default-user-locale-editor.component.html',
|
||||||
|
styleUrls: ['./default-user-locale-editor.component.scss'],
|
||||||
|
providers: [DefaultUserLocaleEditorService]
|
||||||
|
})
|
||||||
|
export class DefaultUserLocaleEditorComponent extends BasePendingChangesComponent implements OnInit {
|
||||||
|
|
||||||
|
isNew = true;
|
||||||
|
formGroup: UntypedFormGroup = null;
|
||||||
|
|
||||||
|
get editorModel(): TenantConfigurationEditorModel { return this._editorModel; }
|
||||||
|
set editorModel(value: TenantConfigurationEditorModel) { this._editorModel = value; }
|
||||||
|
private _editorModel: TenantConfigurationEditorModel;
|
||||||
|
|
||||||
|
timezones: any[];
|
||||||
|
cultures: CultureInfo[];
|
||||||
|
languages = [];
|
||||||
|
protected get canDelete(): boolean {
|
||||||
|
return !this.isNew && this.hasPermission(this.authService.permissionEnum.DeleteTenantConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected get canSave(): boolean {
|
||||||
|
return this.hasPermission(this.authService.permissionEnum.EditTenantConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasPermission(permission: AppPermission): boolean {
|
||||||
|
return this.authService.hasPermission(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected dialog: MatDialog,
|
||||||
|
protected language: TranslateService,
|
||||||
|
protected formService: FormService,
|
||||||
|
protected uiNotificationService: UiNotificationService,
|
||||||
|
protected httpErrorHandlingService: HttpErrorHandlingService,
|
||||||
|
protected authService: AuthService,
|
||||||
|
private logger: LoggingService,
|
||||||
|
private cultureService: CultureService,
|
||||||
|
private tenantConfigurationService: TenantConfigurationService,
|
||||||
|
private languageService: LanguageService,
|
||||||
|
private defaultUserLocaleEditorService: DefaultUserLocaleEditorService,
|
||||||
|
private matomoService: MatomoService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this.languages = this.languageService.getAvailableLanguagesCodes().sort((x, y) => x.localeCompare(y));
|
||||||
|
this.cultures = this.cultureService.getCultureValues().sort((x, y) => x.displayName.localeCompare(y.displayName));
|
||||||
|
this.timezones = moment.tz.names().sort((x, y) => x.localeCompare(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
canDeactivate(): boolean | Observable<boolean> {
|
||||||
|
return this.formGroup ? !this.formGroup.dirty : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.matomoService.trackPageView('Admin: TenantConfigurations');
|
||||||
|
this.getItem((entity) => {
|
||||||
|
this.prepareForm(entity);
|
||||||
|
if (this.formGroup && this.editorModel.belongsToCurrentTenant == false) {
|
||||||
|
this.formGroup.disable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getItem(successFunction: (item: TenantConfiguration) => void) {
|
||||||
|
this.tenantConfigurationService.getCurrentTenantType(TenantConfigurationType.DefaultUserLocale, DefaultUserLocaleEditorResolver.lookupFields())
|
||||||
|
.pipe(map(data => data as TenantConfiguration), takeUntil(this._destroyed))
|
||||||
|
.subscribe(
|
||||||
|
data => successFunction(data),
|
||||||
|
error => this.onCallbackError(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCallbackError(errorResponse: HttpErrorResponse) {
|
||||||
|
|
||||||
|
console.log("Error:", errorResponse);
|
||||||
|
|
||||||
|
const error: HttpError = this.httpErrorHandlingService.getError(errorResponse);
|
||||||
|
if (error.statusCode === 400) {
|
||||||
|
this.editorModel.validationErrorModel.fromJSONObject(errorResponse.error);
|
||||||
|
if(errorResponse.error.code === ResponseErrorCode.TenantConfigurationTypeCanNotChange){
|
||||||
|
this.uiNotificationService.snackBarNotification(errorResponse.error.error, SnackBarNotificationLevel.Error);
|
||||||
|
}
|
||||||
|
if(errorResponse.error.code === ResponseErrorCode.MultipleTenantConfigurationTypeNotAllowed){
|
||||||
|
this.uiNotificationService.snackBarNotification(errorResponse.error.error, SnackBarNotificationLevel.Error);
|
||||||
|
}
|
||||||
|
this.formService.validateAllFormFields(this.formGroup);
|
||||||
|
} else {
|
||||||
|
this.uiNotificationService.snackBarNotification(error.getMessagesString(), SnackBarNotificationLevel.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onCallbackSuccess(data?: any): void {
|
||||||
|
|
||||||
|
console.log("Success:", data);
|
||||||
|
|
||||||
|
this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
|
||||||
|
this.refreshData();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
prepareForm(data: TenantConfiguration) {
|
||||||
|
try {
|
||||||
|
this.editorModel = data ? new TenantConfigurationEditorModel().fromModel(data) : new TenantConfigurationEditorModel();
|
||||||
|
|
||||||
|
this.buildForm();
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('Could not parse TenantConfiguration item: ' + data + error);
|
||||||
|
this.uiNotificationService.snackBarNotification(this.language.instant('COMMONS.ERRORS.DEFAULT'), SnackBarNotificationLevel.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildForm() {
|
||||||
|
this.formGroup = this.editorModel.buildForm(null, !this.authService.hasPermission(AppPermission.EditTenantConfiguration));
|
||||||
|
this.defaultUserLocaleEditorService.setValidationErrorModel(this.editorModel.validationErrorModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshData(): void {
|
||||||
|
this.getItem((entity) => {
|
||||||
|
this.prepareForm(entity);
|
||||||
|
if (this.formGroup && this.editorModel.belongsToCurrentTenant == false) {
|
||||||
|
this.formGroup.disable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
persistEntity(onSuccess?: (response) => void): void {
|
||||||
|
const formData = this.formService.getValue(this.formGroup.value) as TenantConfigurationPersist;
|
||||||
|
|
||||||
|
this.tenantConfigurationService.persist(formData)
|
||||||
|
.pipe(takeUntil(this._destroyed)).subscribe(
|
||||||
|
complete => onSuccess ? onSuccess(complete) : this.onCallbackSuccess(complete),
|
||||||
|
error => this.onCallbackError(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
formSubmit(): void {
|
||||||
|
this.clearErrorModel();
|
||||||
|
this.formService.removeAllBackEndErrors(this.formGroup);
|
||||||
|
this.formService.touchAllFormFields(this.formGroup);
|
||||||
|
if (!this.isFormValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.persistEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public isFormValid() {
|
||||||
|
return this.formGroup.valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public delete() {
|
||||||
|
const value = this.formGroup.value;
|
||||||
|
if (value.id) {
|
||||||
|
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
||||||
|
maxWidth: '300px',
|
||||||
|
data: {
|
||||||
|
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.RESET-TO-DEFAULT'),
|
||||||
|
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
|
||||||
|
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
this.tenantConfigurationService.delete(value.id).pipe(takeUntil(this._destroyed))
|
||||||
|
.subscribe(
|
||||||
|
complete => this.onCallbackDeleteSuccessConfig(),
|
||||||
|
error => this.onCallbackError(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCallbackDeleteSuccessConfig(data?: any): void {
|
||||||
|
|
||||||
|
console.log("Success Delete:", data);
|
||||||
|
|
||||||
|
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-RESET'), SnackBarNotificationLevel.Success);
|
||||||
|
this.prepareForm(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
clearErrorModel() {
|
||||||
|
this.editorModel.validationErrorModel.clear();
|
||||||
|
this.formService.validateAllFormFields(this.formGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
displayCultureFn(culture?: CultureInfo): string | undefined {
|
||||||
|
|
||||||
|
if (culture == null
|
||||||
|
|| culture.displayName == null
|
||||||
|
|| culture.nativeName == null)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
|
return culture.displayName + '-' + culture.nativeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
|
||||||
|
import { TenantConfigurationType } from "@app/core/common/enum/tenant-configuration-type";
|
||||||
|
import { DefaultUserLocaleTenantConfiguration, DefaultUserLocaleTenantConfigurationPersist, TenantConfiguration, TenantConfigurationPersist } from "@app/core/model/tenant-configuaration/tenant-configuration";
|
||||||
|
import { BaseEditorModel } from "@common/base/base-form-editor-model";
|
||||||
|
import { BackendErrorValidator } from "@common/forms/validation/custom-validator";
|
||||||
|
import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model";
|
||||||
|
import { Validation, ValidationContext } from "@common/forms/validation/validation-context";
|
||||||
|
|
||||||
|
export class TenantConfigurationEditorModel extends BaseEditorModel implements TenantConfigurationPersist {
|
||||||
|
type: TenantConfigurationType;
|
||||||
|
defaultUserLocale: DefaultUserLocaleTenantConfigurationEditorModel = new DefaultUserLocaleTenantConfigurationEditorModel(this.validationErrorModel);
|
||||||
|
|
||||||
|
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
|
||||||
|
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||||
|
|
||||||
|
constructor() { super(); this.type = TenantConfigurationType.DefaultUserLocale; }
|
||||||
|
|
||||||
|
public fromModel(item: TenantConfiguration): TenantConfigurationEditorModel {
|
||||||
|
if (item) {
|
||||||
|
super.fromModel(item);
|
||||||
|
this.type = item.type;
|
||||||
|
if (item.defaultUserLocale) this.defaultUserLocale = new DefaultUserLocaleTenantConfigurationEditorModel(this.validationErrorModel).fromModel(item.defaultUserLocale);
|
||||||
|
} else {
|
||||||
|
this.type = TenantConfigurationType.DefaultUserLocale;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup {
|
||||||
|
if (context == null) { context = this.createValidationContext(); }
|
||||||
|
|
||||||
|
return this.formBuilder.group({
|
||||||
|
id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
|
||||||
|
type: [{ value: this.type, disabled: disabled }, context.getValidation('type').validators],
|
||||||
|
hash: [{ value: this.hash, disabled: disabled }, context.getValidation('hash').validators],
|
||||||
|
defaultUserLocale: this.defaultUserLocale.buildForm({
|
||||||
|
rootPath: `defaultUserLocale.`,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createValidationContext(): ValidationContext {
|
||||||
|
const baseContext: ValidationContext = new ValidationContext();
|
||||||
|
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||||
|
baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] });
|
||||||
|
baseValidationArray.push({ key: 'type', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'type')] });
|
||||||
|
baseValidationArray.push({ key: 'hash', validators: [] });
|
||||||
|
|
||||||
|
baseContext.validation = baseValidationArray;
|
||||||
|
return baseContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DefaultUserLocaleTenantConfigurationEditorModel implements DefaultUserLocaleTenantConfigurationPersist {
|
||||||
|
timezone: string;
|
||||||
|
language: string;
|
||||||
|
culture: string;
|
||||||
|
|
||||||
|
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||||
|
) { }
|
||||||
|
|
||||||
|
public fromModel(item: DefaultUserLocaleTenantConfiguration): DefaultUserLocaleTenantConfigurationEditorModel {
|
||||||
|
if (item) {
|
||||||
|
this.timezone = item.timezone;
|
||||||
|
this.language = item.language;
|
||||||
|
this.culture = item.culture;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
buildForm(params?: {
|
||||||
|
context?: ValidationContext,
|
||||||
|
disabled?: boolean,
|
||||||
|
rootPath?: string
|
||||||
|
}): UntypedFormGroup {
|
||||||
|
let { context = null, disabled = false, rootPath } = params ?? {}
|
||||||
|
if (context == null) {
|
||||||
|
context = DefaultUserLocaleTenantConfigurationEditorModel.createValidationContext({
|
||||||
|
validationErrorModel: this.validationErrorModel,
|
||||||
|
rootPath
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const form: UntypedFormGroup = this.formBuilder.group({
|
||||||
|
timezone: [{ value: this.timezone, disabled: disabled }, context.getValidation('timezone').validators],
|
||||||
|
language: [{ value: this.language, disabled: disabled }, context.getValidation('language').validators],
|
||||||
|
culture: [{ value: this.culture, disabled: disabled }, context.getValidation('culture').validators],
|
||||||
|
});
|
||||||
|
|
||||||
|
return form;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static createValidationContext(params: {
|
||||||
|
rootPath?: string,
|
||||||
|
validationErrorModel: ValidationErrorModel
|
||||||
|
}): ValidationContext {
|
||||||
|
const { rootPath = '', validationErrorModel } = params;
|
||||||
|
|
||||||
|
const baseContext: ValidationContext = new ValidationContext();
|
||||||
|
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||||
|
baseValidationArray.push({ key: 'timezone', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}timezone`)] });
|
||||||
|
baseValidationArray.push({ key: 'language', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}language`)] });
|
||||||
|
baseValidationArray.push({ key: 'culture', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}culture`)] });
|
||||||
|
|
||||||
|
baseContext.validation = baseValidationArray;
|
||||||
|
return baseContext;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { TenantConfigurationType } from '@app/core/common/enum/tenant-configuration-type';
|
||||||
|
import { DefaultUserLocaleTenantConfiguration, TenantConfiguration } from '@app/core/model/tenant-configuaration/tenant-configuration';
|
||||||
|
import { TenantConfigurationService } from '@app/core/services/tenant-configuration/tenant-configuration.service';
|
||||||
|
import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
|
||||||
|
import { BaseEditorResolver } from '@common/base/base-editor.resolver';
|
||||||
|
import { takeUntil, tap } from 'rxjs/operators';
|
||||||
|
import { nameof } from 'ts-simple-nameof';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DefaultUserLocaleEditorResolver extends BaseEditorResolver {
|
||||||
|
|
||||||
|
constructor(private tenantConfigurationService: TenantConfigurationService, private breadcrumbService: BreadcrumbService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static lookupFields(): string[] {
|
||||||
|
return [
|
||||||
|
...BaseEditorResolver.lookupFields(),
|
||||||
|
nameof<TenantConfiguration>(x => x.id),
|
||||||
|
nameof<TenantConfiguration>(x => x.type),
|
||||||
|
nameof<TenantConfiguration>(x => x.defaultUserLocale),
|
||||||
|
|
||||||
|
[nameof<TenantConfiguration>(x => x.defaultUserLocale), nameof<DefaultUserLocaleTenantConfiguration>(x => x.culture)].join('.'),
|
||||||
|
[nameof<TenantConfiguration>(x => x.defaultUserLocale), nameof<DefaultUserLocaleTenantConfiguration>(x => x.language)].join('.'),
|
||||||
|
[nameof<TenantConfiguration>(x => x.defaultUserLocale), nameof<DefaultUserLocaleTenantConfiguration>(x => x.timezone)].join('.'),
|
||||||
|
|
||||||
|
|
||||||
|
nameof<TenantConfiguration>(x => x.createdAt),
|
||||||
|
nameof<TenantConfiguration>(x => x.updatedAt),
|
||||||
|
nameof<TenantConfiguration>(x => x.hash),
|
||||||
|
nameof<TenantConfiguration>(x => x.isActive)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve() {
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
...DefaultUserLocaleEditorResolver.lookupFields()
|
||||||
|
];
|
||||||
|
|
||||||
|
return this.tenantConfigurationService.getCurrentTenantType(TenantConfigurationType.DefaultUserLocale, fields).pipe(takeUntil(this._destroyed));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DefaultUserLocaleEditorService {
|
||||||
|
private validationErrorModel: ValidationErrorModel;
|
||||||
|
|
||||||
|
public setValidationErrorModel(validationErrorModel: ValidationErrorModel): void {
|
||||||
|
this.validationErrorModel = validationErrorModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getValidationErrorModel(): ValidationErrorModel {
|
||||||
|
return this.validationErrorModel;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-10 offset-md-1 tenant-configuration-component">
|
||||||
|
<div class="row align-items-center mb-4 mt-4" >
|
||||||
|
<div class="col-md col-12">
|
||||||
|
<h3>{{'TENANT-CONFIGURATION-EDITOR.TITLE' | translate}}</h3>
|
||||||
|
<app-navigation-breadcrumb />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mat-card appearance="outlined">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>{{'TENANT-CONFIGURATION-EDITOR.TITLE' | translate}}</mat-card-title>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="row">
|
||||||
|
<mat-accordion class="col-12 headers-align">
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>{{'TENANT-CONFIGURATION-EDITOR.DEFAULT-USER-LOCALE.TITLE' | translate}}</mat-panel-title>
|
||||||
|
<mat-panel-description>{{'TENANT-CONFIGURATION-EDITOR.DEFAULT-USER-LOCALE.HINT' | translate}}</mat-panel-description>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<ng-template matExpansionPanelContent>
|
||||||
|
<app-tenant-configuration-default-user-locale-editor></app-tenant-configuration-default-user-locale-editor>
|
||||||
|
</ng-template>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>{{'TENANT-CONFIGURATION-EDITOR.CSS-COLORS.TITLE' | translate}}</mat-panel-title>
|
||||||
|
<mat-panel-description>{{'TENANT-CONFIGURATION-EDITOR.CSS-COLORS.HINT' | translate}}</mat-panel-description>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<ng-template matExpansionPanelContent>
|
||||||
|
<app-tenant-configuration-css-colors-editor></app-tenant-configuration-css-colors-editor>
|
||||||
|
</ng-template>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
|
||||||
|
</mat-accordion>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,16 @@
|
||||||
|
.tenant-configuration-component {
|
||||||
|
padding-top: 1em;
|
||||||
|
|
||||||
|
.configuration-container {
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-list-width {
|
||||||
|
width: 15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headers-align .mat-expansion-panel-header-title,
|
||||||
|
.headers-align .mat-expansion-panel-header-description {
|
||||||
|
flex-basis: 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
|
||||||
|
import { BaseComponent } from '@common/base/base.component';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-tenant-configuration-editor-component',
|
||||||
|
templateUrl: 'tenant-configuration-editor.component.html',
|
||||||
|
styleUrls: ['./tenant-configuration-editor.component.scss'],
|
||||||
|
})
|
||||||
|
export class TenantConfigurationEditorComponent extends BaseComponent {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||||
|
import { NgModule } from "@angular/core";
|
||||||
|
import { AutoCompleteModule } from "@app/library/auto-complete/auto-complete.module";
|
||||||
|
import { CommonFormattingModule } from '@common/formatting/common-formatting.module';
|
||||||
|
import { CommonFormsModule } from '@common/forms/common-forms.module';
|
||||||
|
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
|
||||||
|
import { HybridListingModule } from "@common/modules/hybrid-listing/hybrid-listing.module";
|
||||||
|
import { TextFilterModule } from "@common/modules/text-filter/text-filter.module";
|
||||||
|
import { UserSettingsModule } from "@common/modules/user-settings/user-settings.module";
|
||||||
|
import { CommonUiModule } from '@common/ui/common-ui.module';
|
||||||
|
import { NgxDropzoneModule } from "ngx-dropzone";
|
||||||
|
import { RichTextEditorModule } from '@app/library/rich-text-editor/rich-text-editor.module';
|
||||||
|
import { TenantConfigurationRoutingModule } from './tenant-configuration.routing';
|
||||||
|
import { TenantConfigurationEditorComponent } from './editor/tenant-configuration-editor.component';
|
||||||
|
import { CssColorsEditorComponent } from './editor/css-colors/css-colors-editor.component';
|
||||||
|
import { DefaultUserLocaleEditorComponent } from './editor/default-user-locale/default-user-locale-editor.component';
|
||||||
|
import { FormattingModule } from '@app/core/formatting.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonUiModule,
|
||||||
|
CommonFormsModule,
|
||||||
|
ConfirmationDialogModule,
|
||||||
|
TenantConfigurationRoutingModule,
|
||||||
|
NgxDropzoneModule,
|
||||||
|
DragDropModule,
|
||||||
|
FormattingModule,
|
||||||
|
AutoCompleteModule,
|
||||||
|
HybridListingModule,
|
||||||
|
TextFilterModule,
|
||||||
|
UserSettingsModule,
|
||||||
|
CommonFormattingModule,
|
||||||
|
RichTextEditorModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
TenantConfigurationEditorComponent,
|
||||||
|
CssColorsEditorComponent,
|
||||||
|
DefaultUserLocaleEditorComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class TenantConfigurationModule { }
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { AuthGuard } from '@app/core/auth-guard.service';
|
||||||
|
import { TenantConfigurationEditorComponent } from './editor/tenant-configuration-editor.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: TenantConfigurationEditorComponent,
|
||||||
|
canActivate: [AuthGuard]
|
||||||
|
},
|
||||||
|
|
||||||
|
{ path: '**', loadChildren: () => import('@common/modules/page-not-found/page-not-found.module').then(m => m.PageNotFoundModule) },
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule],
|
||||||
|
providers: []
|
||||||
|
})
|
||||||
|
export class TenantConfigurationRoutingModule { }
|
|
@ -1,83 +0,0 @@
|
||||||
<h3>
|
|
||||||
{{label}}
|
|
||||||
<button mat-button class="action-btn" type="button" (click)="addSource()" [disabled]="form.disabled">{{'TENANT-EDITOR.ACTIONS.ADD-SOURCE' | translate}}</button>
|
|
||||||
</h3>
|
|
||||||
<div *ngFor="let source of form.get('sources').controls; let sourceIndex=index;" class="row mb-3">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="row mb-3 d-flex align-items-center">
|
|
||||||
<div class="col-auto d-flex">
|
|
||||||
<mat-card-title>{{'TENANT-EDITOR.FIELDS.SOURCE' | translate}} {{sourceIndex + 1}}</mat-card-title>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto d-flex">
|
|
||||||
<button mat-icon-button class="action-list-icon" matTooltip="{{'TENANT-EDITOR.ACTIONS.REMOVE-SOURCE' | translate}}" (click)="removeSource(sourceIndex)" [disabled]="form.disabled">
|
|
||||||
<mat-icon>delete</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row" >
|
|
||||||
<div class="col-6">
|
|
||||||
<mat-form-field class="w-100">
|
|
||||||
<mat-label>{{'TENANT-EDITOR.FIELDS.URL' | translate}}</mat-label>
|
|
||||||
<input matInput type="text" name="url" [formControl]="source.get('url')" required>
|
|
||||||
<mat-error *ngIf="source.get('url').hasError('backendError')">{{source.get('url').getError('backendError').message}}</mat-error>
|
|
||||||
<mat-error *ngIf="source.get('url').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-6">
|
|
||||||
<mat-form-field class="w-100">
|
|
||||||
<mat-label>{{'TENANT-EDITOR.FIELDS.ISSUER-URL' | translate}}</mat-label>
|
|
||||||
<input matInput type="text" name="issuerUrl" [formControl]="source.get('issuerUrl')" required>
|
|
||||||
<mat-error *ngIf="source.get('issuerUrl').hasError('backendError')">{{source.get('issuerUrl').getError('backendError').message}}</mat-error>
|
|
||||||
<mat-error *ngIf="source.get('issuerUrl').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-6">
|
|
||||||
<mat-form-field class="w-100">
|
|
||||||
<mat-label>{{'TENANT-EDITOR.FIELDS.CLIENT-ID' | translate}}</mat-label>
|
|
||||||
<input matInput type="text" name="clientId" [formControl]="source.get('clientId')" required>
|
|
||||||
<mat-error *ngIf="source.get('clientId').hasError('backendError')">{{source.get('clientId').getError('backendError').message}}</mat-error>
|
|
||||||
<mat-error *ngIf="source.get('clientId').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-6">
|
|
||||||
<mat-form-field class="w-100">
|
|
||||||
<mat-label>{{'TENANT-EDITOR.FIELDS.CLIENT-SECRET' | translate}}</mat-label>
|
|
||||||
<input matInput type="text" name="clientSecret" [formControl]="source.get('clientSecret')" required>
|
|
||||||
<mat-error *ngIf="source.get('clientSecret').hasError('backendError')">{{source.get('clientSecret').getError('backendError').message}}</mat-error>
|
|
||||||
<mat-error *ngIf="source.get('clientSecret').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-6">
|
|
||||||
<mat-form-field class="w-100">
|
|
||||||
<mat-label>{{'TENANT-EDITOR.FIELDS.SCOPE' | translate}}</mat-label>
|
|
||||||
<input matInput type="text" name="scope" [formControl]="source.get('scope')" required>
|
|
||||||
<mat-error *ngIf="source.get('scope').hasError('backendError')">{{source.get('scope').getError('backendError').message}}</mat-error>
|
|
||||||
<mat-error *ngIf="source.get('scope').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-6">
|
|
||||||
<mat-form-field class="chip-list">
|
|
||||||
<mat-label>{{'TENANT-EDITOR.FIELDS.CODES' | translate}}</mat-label>
|
|
||||||
<mat-chip-grid #chipGrid [formControl]="source.get('codes')">
|
|
||||||
<mat-chip-row *ngFor="let code of codes.get(sourceIndex)"
|
|
||||||
(removed)="removeCode(code, sourceIndex)"
|
|
||||||
[editable]="true"
|
|
||||||
(edited)="editCode(code, $event, sourceIndex)">
|
|
||||||
{{code}}
|
|
||||||
<button matChipRemove>
|
|
||||||
<mat-icon>cancel</mat-icon>
|
|
||||||
</button>
|
|
||||||
</mat-chip-row>
|
|
||||||
<input placeholder="{{'TENANT-EDITOR.FIELDS.CODES-PLACEHOLDER' | translate}}"
|
|
||||||
[matChipInputFor]="chipGrid"
|
|
||||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
|
||||||
[matChipInputAddOnBlur]="true"
|
|
||||||
(matChipInputTokenEnd)="addCode($event, sourceIndex)"/>
|
|
||||||
</mat-chip-grid>
|
|
||||||
<mat-error *ngIf="source.get('codes').hasError('backendError')">{{source.get('codes').getError('backendError').message}}</mat-error>
|
|
||||||
<mat-error *ngIf="source.get('codes').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,18 +0,0 @@
|
||||||
.action-btn {
|
|
||||||
border-radius: 30px;
|
|
||||||
background-color: var(--secondary-color);
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding-left: 2em;
|
|
||||||
padding-right: 2em;
|
|
||||||
box-shadow: 0px 3px 6px #1E202029;
|
|
||||||
|
|
||||||
transition-property: background-color, color;
|
|
||||||
transition-duration: 200ms;
|
|
||||||
transition-delay: 50ms;
|
|
||||||
transition-timing-function: ease-in-out;
|
|
||||||
&:disabled{
|
|
||||||
background-color: #CBCBCB;
|
|
||||||
color: #FFF;
|
|
||||||
border: 0px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
import { Component, Input, OnInit } from '@angular/core';
|
|
||||||
import { UntypedFormArray } from '@angular/forms';
|
|
||||||
import { MatChipEditedEvent, MatChipInputEvent } from '@angular/material/chips';
|
|
||||||
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
|
|
||||||
import { BaseComponent } from '@common/base/base.component';
|
|
||||||
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
|
|
||||||
import { TenantDepositConfigEditorModel, TenantEditorModel, TenantSourceEditorModel } from '../tenant-editor.model';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-tenant-source-component',
|
|
||||||
templateUrl: 'tenant-source.component.html',
|
|
||||||
styleUrls: ['./tenant-source.component.scss']
|
|
||||||
})
|
|
||||||
export class TenantSourceComponent extends BaseComponent implements OnInit {
|
|
||||||
|
|
||||||
@Input() form;
|
|
||||||
@Input() validationErrorModel: ValidationErrorModel = null;
|
|
||||||
@Input() validationRootPath: string = null;
|
|
||||||
@Input() codes: Map<number, string[]>;
|
|
||||||
@Input() label: string = null;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public enumUtils: EnumUtils,
|
|
||||||
) { super(); }
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// source
|
|
||||||
//
|
|
||||||
addSource(): void {
|
|
||||||
const formArray = this.form.get('sources') as UntypedFormArray;
|
|
||||||
this.codes.set(formArray.length, []);
|
|
||||||
const source: TenantSourceEditorModel = new TenantSourceEditorModel(this.validationErrorModel);
|
|
||||||
formArray.push(source.buildForm({ rootPath: this.validationRootPath + 'sources[' + formArray.length + '].' }));
|
|
||||||
}
|
|
||||||
|
|
||||||
removeSource(sourceIndex: number): void {
|
|
||||||
this.codes.delete((this.form.get('sources') as UntypedFormArray).length);
|
|
||||||
(this.form.get('sources') as UntypedFormArray).removeAt(sourceIndex);
|
|
||||||
|
|
||||||
// Reapply validators
|
|
||||||
TenantDepositConfigEditorModel.reapplySourcesFieldsValidators(
|
|
||||||
{
|
|
||||||
formArray: this.form.get('sources') as UntypedFormArray,
|
|
||||||
validationErrorModel: this.validationErrorModel,
|
|
||||||
rootPath: this.validationRootPath
|
|
||||||
}
|
|
||||||
)
|
|
||||||
this.form.get('sources').markAsDirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
// source codes
|
|
||||||
|
|
||||||
addCode(event: MatChipInputEvent, key: number): void {
|
|
||||||
const value = (event.value || '').trim();
|
|
||||||
|
|
||||||
if (value){
|
|
||||||
const values = this.codes.get(key);
|
|
||||||
values.push(value);
|
|
||||||
this.codes.set(key, values);
|
|
||||||
}
|
|
||||||
event.chipInput!.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
removeCode(code: string, key: number): void {
|
|
||||||
const values = this.codes.get(key);
|
|
||||||
if (values){
|
|
||||||
const index = values.indexOf(code);
|
|
||||||
|
|
||||||
if (index >= 0) {
|
|
||||||
values.splice(index, 1);
|
|
||||||
this.codes.set(key, values);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
editCode(code: string, event: MatChipEditedEvent, key: number) {
|
|
||||||
const values = this.codes.get(key);
|
|
||||||
if (values){
|
|
||||||
const value = event.value.trim();
|
|
||||||
|
|
||||||
// Remove code if it no longer has a value
|
|
||||||
if (!value) {
|
|
||||||
this.removeCode(code, key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const index = values.indexOf(code);
|
|
||||||
if (index >= 0) {
|
|
||||||
values[index] = value;
|
|
||||||
this.codes.set(key, values);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -57,25 +57,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Deposit -->
|
|
||||||
<div class="col-12">
|
|
||||||
<app-tenant-source-component
|
|
||||||
[form]="formGroup.get('config').get('deposit')"
|
|
||||||
[validationErrorModel]="editorModel.validationErrorModel"
|
|
||||||
[validationRootPath]="'config.deposit.'"
|
|
||||||
[codes]="depositCodes"
|
|
||||||
[label]="'TENANT-EDITOR.FIELDS.DEPOSIT' | translate">
|
|
||||||
</app-tenant-source-component>
|
|
||||||
</div>
|
|
||||||
<div class="col-12">
|
|
||||||
<app-tenant-source-component
|
|
||||||
[form]="formGroup.get('config').get('fileTransformers')"
|
|
||||||
[validationErrorModel]="editorModel.validationErrorModel"
|
|
||||||
[validationRootPath]="'config.fileTransformers.'"
|
|
||||||
[codes]="fileTransformersCodes"
|
|
||||||
[label]="'TENANT-EDITOR.FIELDS.FILE-TRANSFORMERS' | translate">
|
|
||||||
</app-tenant-source-component>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
|
|
@ -108,10 +108,6 @@ export class TenantEditorComponent extends BaseEditor<TenantEditorModel, Tenant>
|
||||||
try {
|
try {
|
||||||
this.editorModel = data ? new TenantEditorModel().fromModel(data) : new TenantEditorModel();
|
this.editorModel = data ? new TenantEditorModel().fromModel(data) : new TenantEditorModel();
|
||||||
|
|
||||||
if(data && data.config){
|
|
||||||
if(data.config.deposit && data.config.deposit.sources) data.config.deposit.sources.forEach((source, index) => this.depositCodes.set(index, source.codes));
|
|
||||||
if(data.config.fileTransformers && data.config.fileTransformers.sources) data.config.fileTransformers.sources.forEach((source, index) => this.fileTransformersCodes.set(index, source.codes));
|
|
||||||
}
|
|
||||||
this.isDeleted = data ? data.isActive === IsActive.Inactive : false;
|
this.isDeleted = data ? data.isActive === IsActive.Inactive : false;
|
||||||
this.buildForm();
|
this.buildForm();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
|
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
|
||||||
import { Tenant, TenantConfig, TenantConfigPersist, TenantDepositConfig, TenantDepositConfigPersist, TenantFileTransformersConfig, TenantFileTransformersConfigPersist, TenantPersist, TenantSource, TenantSourcePersist } from "@app/core/model/tenant/tenant";
|
import { Tenant, TenantPersist } from "@app/core/model/tenant/tenant";
|
||||||
import { BaseEditorModel } from "@common/base/base-form-editor-model";
|
import { BaseEditorModel } from "@common/base/base-form-editor-model";
|
||||||
import { BackendErrorValidator } from "@common/forms/validation/custom-validator";
|
import { BackendErrorValidator } from "@common/forms/validation/custom-validator";
|
||||||
import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model";
|
import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model";
|
||||||
|
@ -9,7 +9,6 @@ export class TenantEditorModel extends BaseEditorModel implements TenantPersist
|
||||||
name: string;
|
name: string;
|
||||||
code: string;
|
code: string;
|
||||||
description: string;
|
description: string;
|
||||||
config: TenantConfigEditorModel = new TenantConfigEditorModel();
|
|
||||||
permissions: string[];
|
permissions: string[];
|
||||||
|
|
||||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
|
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
|
||||||
|
@ -23,7 +22,6 @@ export class TenantEditorModel extends BaseEditorModel implements TenantPersist
|
||||||
this.name = item.name;
|
this.name = item.name;
|
||||||
this.code = item.code;
|
this.code = item.code;
|
||||||
this.description = item.description;
|
this.description = item.description;
|
||||||
if (item.config) this.config = new TenantConfigEditorModel(this.validationErrorModel).fromModel(item.config);
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -36,9 +34,6 @@ export class TenantEditorModel extends BaseEditorModel implements TenantPersist
|
||||||
name: [{ value: this.name, disabled: disabled }, context.getValidation('name').validators],
|
name: [{ value: this.name, disabled: disabled }, context.getValidation('name').validators],
|
||||||
code: [{ value: this.code, disabled: disabled }, context.getValidation('code').validators],
|
code: [{ value: this.code, disabled: disabled }, context.getValidation('code').validators],
|
||||||
description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
|
description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
|
||||||
config: this.config.buildForm({
|
|
||||||
rootPath: `config.`,
|
|
||||||
}),
|
|
||||||
hash: [{ value: this.hash, disabled: disabled }, context.getValidation('hash').validators]
|
hash: [{ value: this.hash, disabled: disabled }, context.getValidation('hash').validators]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -55,301 +50,4 @@ export class TenantEditorModel extends BaseEditorModel implements TenantPersist
|
||||||
baseContext.validation = baseValidationArray;
|
baseContext.validation = baseValidationArray;
|
||||||
return baseContext;
|
return baseContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
static reApplyDepositSourcesValidators(params: {
|
|
||||||
formGroup: UntypedFormGroup,
|
|
||||||
validationErrorModel: ValidationErrorModel,
|
|
||||||
}): void {
|
|
||||||
|
|
||||||
const { formGroup, validationErrorModel } = params;
|
|
||||||
const control = formGroup?.get('config').get('deposit');
|
|
||||||
TenantDepositConfigEditorModel.reapplySourcesFieldsValidators({
|
|
||||||
formArray: control.get('sources') as UntypedFormArray,
|
|
||||||
rootPath: `config.deposit.`,
|
|
||||||
validationErrorModel: validationErrorModel
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static reApplyFileTransformerSourcesValidators(params: {
|
|
||||||
formGroup: UntypedFormGroup,
|
|
||||||
validationErrorModel: ValidationErrorModel,
|
|
||||||
}): void {
|
|
||||||
|
|
||||||
const { formGroup, validationErrorModel } = params;
|
|
||||||
const control = formGroup?.get('config').get('fileTransformers');
|
|
||||||
TenantDepositConfigEditorModel.reapplySourcesFieldsValidators({
|
|
||||||
formArray: control.get('sources') as UntypedFormArray,
|
|
||||||
rootPath: `config.fileTransformers.`,
|
|
||||||
validationErrorModel: validationErrorModel
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TenantConfigEditorModel implements TenantConfigPersist {
|
|
||||||
deposit: TenantDepositConfigEditorModel = new TenantDepositConfigEditorModel();
|
|
||||||
fileTransformers: TenantFileTransformersConfigEditorModel = new TenantFileTransformersConfigEditorModel();
|
|
||||||
|
|
||||||
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public fromModel(item: TenantConfig): TenantConfigEditorModel {
|
|
||||||
if (item) {
|
|
||||||
if (item.deposit) this.deposit = new TenantDepositConfigEditorModel(this.validationErrorModel).fromModel(item.deposit);
|
|
||||||
if (item.fileTransformers) this.fileTransformers = new TenantFileTransformersConfigEditorModel(this.validationErrorModel).fromModel(item.fileTransformers);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildForm(params?: {
|
|
||||||
context?: ValidationContext,
|
|
||||||
disabled?: boolean,
|
|
||||||
rootPath?: string
|
|
||||||
}): UntypedFormGroup {
|
|
||||||
let { context = null, disabled = false, rootPath } = params ?? {}
|
|
||||||
if (context == null) {
|
|
||||||
context = TenantConfigEditorModel.createValidationContext({
|
|
||||||
validationErrorModel: this.validationErrorModel,
|
|
||||||
rootPath
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.formBuilder.group({
|
|
||||||
deposit: this.deposit.buildForm({
|
|
||||||
rootPath: `${rootPath}deposit.`
|
|
||||||
}),
|
|
||||||
fileTransformers: this.fileTransformers.buildForm({
|
|
||||||
rootPath: `${rootPath}fileTransformers.`
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static createValidationContext(params: {
|
|
||||||
rootPath?: string,
|
|
||||||
validationErrorModel: ValidationErrorModel
|
|
||||||
}): ValidationContext {
|
|
||||||
const { rootPath = '', validationErrorModel } = params;
|
|
||||||
|
|
||||||
const baseContext: ValidationContext = new ValidationContext();
|
|
||||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
|
||||||
|
|
||||||
baseContext.validation = baseValidationArray;
|
|
||||||
return baseContext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TenantDepositConfigEditorModel implements TenantDepositConfigPersist {
|
|
||||||
sources: TenantSourceEditorModel[]= [];
|
|
||||||
|
|
||||||
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public fromModel(item: TenantDepositConfig): TenantDepositConfigEditorModel {
|
|
||||||
if (item) {
|
|
||||||
if (item.sources) { item.sources.map(x => this.sources.push(new TenantSourceEditorModel(this.validationErrorModel).fromModel(x))); }
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildForm(params?: {
|
|
||||||
context?: ValidationContext,
|
|
||||||
disabled?: boolean,
|
|
||||||
rootPath?: string
|
|
||||||
}): UntypedFormGroup {
|
|
||||||
let { context = null, disabled = false, rootPath } = params ?? {}
|
|
||||||
if (context == null) {
|
|
||||||
context = TenantDepositConfigEditorModel.createValidationContext({
|
|
||||||
validationErrorModel: this.validationErrorModel,
|
|
||||||
rootPath
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.formBuilder.group({
|
|
||||||
sources: this.formBuilder.array(
|
|
||||||
(this.sources ?? []).map(
|
|
||||||
(item, index) => item.buildForm({
|
|
||||||
rootPath: `${rootPath}sources[${index}].`
|
|
||||||
})
|
|
||||||
), context.getValidation('sources')
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static createValidationContext(params: {
|
|
||||||
rootPath?: string,
|
|
||||||
validationErrorModel: ValidationErrorModel
|
|
||||||
}): ValidationContext {
|
|
||||||
const { rootPath = '', validationErrorModel } = params;
|
|
||||||
|
|
||||||
const baseContext: ValidationContext = new ValidationContext();
|
|
||||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
|
||||||
baseValidationArray.push({ key: 'sources', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}sources`)] });
|
|
||||||
|
|
||||||
baseContext.validation = baseValidationArray;
|
|
||||||
return baseContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
static reapplySourcesFieldsValidators(params: {
|
|
||||||
formArray: UntypedFormArray,
|
|
||||||
validationErrorModel: ValidationErrorModel,
|
|
||||||
rootPath: string
|
|
||||||
}): void {
|
|
||||||
const { validationErrorModel, rootPath, formArray } = params;
|
|
||||||
formArray?.controls?.forEach(
|
|
||||||
(control, index) => TenantSourceEditorModel.reapplyValidators({
|
|
||||||
formGroup: control as UntypedFormGroup,
|
|
||||||
rootPath: `${rootPath}sources[${index}].`,
|
|
||||||
validationErrorModel: validationErrorModel
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TenantFileTransformersConfigEditorModel implements TenantFileTransformersConfigPersist {
|
|
||||||
sources: TenantSourceEditorModel[]= [];
|
|
||||||
|
|
||||||
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public fromModel(item: TenantFileTransformersConfig): TenantFileTransformersConfigEditorModel {
|
|
||||||
if (item) {
|
|
||||||
if (item.sources) { item.sources.map(x => this.sources.push(new TenantSourceEditorModel(this.validationErrorModel).fromModel(x))); }
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildForm(params?: {
|
|
||||||
context?: ValidationContext,
|
|
||||||
disabled?: boolean,
|
|
||||||
rootPath?: string
|
|
||||||
}): UntypedFormGroup {
|
|
||||||
let { context = null, disabled = false, rootPath } = params ?? {}
|
|
||||||
if (context == null) {
|
|
||||||
context = TenantFileTransformersConfigEditorModel.createValidationContext({
|
|
||||||
validationErrorModel: this.validationErrorModel,
|
|
||||||
rootPath
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.formBuilder.group({
|
|
||||||
sources: this.formBuilder.array(
|
|
||||||
(this.sources ?? []).map(
|
|
||||||
(item, index) => item.buildForm({
|
|
||||||
rootPath: `${rootPath}sources[${index}].`
|
|
||||||
})
|
|
||||||
), context.getValidation('sources')
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static createValidationContext(params: {
|
|
||||||
rootPath?: string,
|
|
||||||
validationErrorModel: ValidationErrorModel
|
|
||||||
}): ValidationContext {
|
|
||||||
const { rootPath = '', validationErrorModel } = params;
|
|
||||||
|
|
||||||
const baseContext: ValidationContext = new ValidationContext();
|
|
||||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
|
||||||
baseValidationArray.push({ key: 'sources', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}sources`)] });
|
|
||||||
|
|
||||||
baseContext.validation = baseValidationArray;
|
|
||||||
return baseContext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TenantSourceEditorModel implements TenantSourcePersist {
|
|
||||||
url: string;
|
|
||||||
codes: string[]= [];
|
|
||||||
issuerUrl: string;
|
|
||||||
clientId: string;
|
|
||||||
clientSecret: string;
|
|
||||||
scope: string;
|
|
||||||
|
|
||||||
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public fromModel(item: TenantSource): TenantSourceEditorModel {
|
|
||||||
if (item) {
|
|
||||||
this.url = item.url;
|
|
||||||
//if (item.codes) { item.codes.map(x => this.codes.push(new SourceCodeEditorModel().fromModel(x))); }
|
|
||||||
this.codes = item.codes;
|
|
||||||
this.issuerUrl = item.issuerUrl;
|
|
||||||
this.clientId = item.clientId;
|
|
||||||
this.clientSecret = item.clientSecret;
|
|
||||||
this.scope = item.scope;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildForm(params?: {
|
|
||||||
context?: ValidationContext,
|
|
||||||
disabled?: boolean,
|
|
||||||
rootPath?: string
|
|
||||||
}): UntypedFormGroup {
|
|
||||||
let { context = null, disabled = false, rootPath } = params ?? {}
|
|
||||||
if (context == null) {
|
|
||||||
context = TenantSourceEditorModel.createValidationContext({
|
|
||||||
validationErrorModel: this.validationErrorModel,
|
|
||||||
rootPath
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.formBuilder.group({
|
|
||||||
url: [{ value: this.url, disabled: disabled }, context.getValidation('url').validators],
|
|
||||||
issuerUrl: [{ value: this.issuerUrl, disabled: disabled }, context.getValidation('issuerUrl').validators],
|
|
||||||
clientId: [{ value: this.clientId, disabled: disabled }, context.getValidation('clientId').validators],
|
|
||||||
clientSecret: [{ value: this.clientSecret, disabled: disabled }, context.getValidation('clientSecret').validators],
|
|
||||||
scope: [{ value: this.scope, disabled: disabled }, context.getValidation('scope').validators],
|
|
||||||
codes: [{ value: this.codes, disabled: disabled }, context.getValidation('codes').validators],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static createValidationContext(params: {
|
|
||||||
rootPath?: string,
|
|
||||||
validationErrorModel: ValidationErrorModel
|
|
||||||
}): ValidationContext {
|
|
||||||
const { rootPath = '', validationErrorModel } = params;
|
|
||||||
|
|
||||||
const baseContext: ValidationContext = new ValidationContext();
|
|
||||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
|
||||||
baseValidationArray.push({ key: 'url', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}url`)] });
|
|
||||||
baseValidationArray.push({ key: 'codes', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}codes`)] });
|
|
||||||
baseValidationArray.push({ key: 'issuerUrl', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}issuerUrl`)] });
|
|
||||||
baseValidationArray.push({ key: 'clientId', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}clientId`)] });
|
|
||||||
baseValidationArray.push({ key: 'clientSecret', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}clientSecret`)] });
|
|
||||||
baseValidationArray.push({ key: 'scope', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}scope`)] });
|
|
||||||
|
|
||||||
baseContext.validation = baseValidationArray;
|
|
||||||
return baseContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
static reapplyValidators(params: {
|
|
||||||
formGroup: UntypedFormGroup,
|
|
||||||
validationErrorModel: ValidationErrorModel,
|
|
||||||
rootPath: string
|
|
||||||
}): void {
|
|
||||||
|
|
||||||
const { formGroup, rootPath, validationErrorModel } = params;
|
|
||||||
const context = TenantSourceEditorModel.createValidationContext({
|
|
||||||
rootPath,
|
|
||||||
validationErrorModel
|
|
||||||
});
|
|
||||||
|
|
||||||
['url', 'codes', 'issuerUrl', 'clientId', 'clientSecret', 'scope'].forEach(keyField => {
|
|
||||||
const control = formGroup?.get(keyField);
|
|
||||||
control?.clearValidators();
|
|
||||||
control?.addValidators(context.getValidation(keyField).validators);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||||
import { SourceCode, Tenant, TenantConfig, TenantDepositConfig, TenantSource } from '@app/core/model/tenant/tenant';
|
import { Tenant } from '@app/core/model/tenant/tenant';
|
||||||
import { TenantService } from '@app/core/services/tenant/tenant.service';
|
import { TenantService } from '@app/core/services/tenant/tenant.service';
|
||||||
import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
|
import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
|
||||||
import { BaseEditorResolver } from '@common/base/base-editor.resolver';
|
import { BaseEditorResolver } from '@common/base/base-editor.resolver';
|
||||||
|
@ -23,20 +23,6 @@ export class TenantEditorResolver extends BaseEditorResolver {
|
||||||
nameof<Tenant>(x => x.code),
|
nameof<Tenant>(x => x.code),
|
||||||
nameof<Tenant>(x => x.description),
|
nameof<Tenant>(x => x.description),
|
||||||
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.deposit), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.url)].join('.'),
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.deposit), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.issuerUrl)].join('.'),
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.deposit), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.clientId)].join('.'),
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.deposit), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.clientSecret)].join('.'),
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.deposit), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.scope)].join('.'),
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.deposit), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.codes)].join('.'),
|
|
||||||
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.fileTransformers), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.url)].join('.'),
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.fileTransformers), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.issuerUrl)].join('.'),
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.fileTransformers), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.clientId)].join('.'),
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.fileTransformers), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.clientSecret)].join('.'),
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.fileTransformers), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.scope)].join('.'),
|
|
||||||
[nameof<Tenant>(x => x.config), nameof<TenantConfig>(x => x.fileTransformers), nameof<TenantDepositConfig>(x => x.sources), nameof<TenantSource>(x => x.codes)].join('.'),
|
|
||||||
|
|
||||||
|
|
||||||
nameof<Tenant>(x => x.createdAt),
|
nameof<Tenant>(x => x.createdAt),
|
||||||
nameof<Tenant>(x => x.updatedAt),
|
nameof<Tenant>(x => x.updatedAt),
|
||||||
|
|
|
@ -14,7 +14,6 @@ import { TenantEditorComponent } from './editor/tenant-editor.component';
|
||||||
import { TenantListingComponent } from './listing/tenant-listing.component';
|
import { TenantListingComponent } from './listing/tenant-listing.component';
|
||||||
import { TenantListingFiltersComponent } from "./listing/filters/tenant-listing-filters.component";
|
import { TenantListingFiltersComponent } from "./listing/filters/tenant-listing-filters.component";
|
||||||
import { RichTextEditorModule } from '@app/library/rich-text-editor/rich-text-editor.module';
|
import { RichTextEditorModule } from '@app/library/rich-text-editor/rich-text-editor.module';
|
||||||
import { TenantSourceComponent } from './editor/source/tenant-source.component';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -34,8 +33,7 @@ import { TenantSourceComponent } from './editor/source/tenant-source.component';
|
||||||
declarations: [
|
declarations: [
|
||||||
TenantEditorComponent,
|
TenantEditorComponent,
|
||||||
TenantListingComponent,
|
TenantListingComponent,
|
||||||
TenantListingFiltersComponent,
|
TenantListingFiltersComponent
|
||||||
TenantSourceComponent
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class TenantModule { }
|
export class TenantModule { }
|
||||||
|
|
|
@ -116,6 +116,7 @@ export class SidebarComponent implements OnInit {
|
||||||
if (this.authentication.hasPermission(AppPermission.ViewReferenceTypePage)) this.adminItems.routes.push({ path: '/reference-type', title: 'SIDE-BAR.REFERENCE-TYPES', icon: 'add_link' });
|
if (this.authentication.hasPermission(AppPermission.ViewReferenceTypePage)) this.adminItems.routes.push({ path: '/reference-type', title: 'SIDE-BAR.REFERENCE-TYPES', icon: 'add_link' });
|
||||||
if (this.authentication.hasPermission(AppPermission.ViewPrefillingSourcePage)) this.adminItems.routes.push({ path: '/prefilling-sources', title: 'SIDE-BAR.PREFILLING-SOURCES', icon: 'quick_reference_all' });
|
if (this.authentication.hasPermission(AppPermission.ViewPrefillingSourcePage)) this.adminItems.routes.push({ path: '/prefilling-sources', title: 'SIDE-BAR.PREFILLING-SOURCES', icon: 'quick_reference_all' });
|
||||||
if (this.authentication.hasPermission(AppPermission.ViewTenantPage)) this.adminItems.routes.push({ path: '/tenants', title: 'SIDE-BAR.TENANTS', icon: 'tenancy' });
|
if (this.authentication.hasPermission(AppPermission.ViewTenantPage)) this.adminItems.routes.push({ path: '/tenants', title: 'SIDE-BAR.TENANTS', icon: 'tenancy' });
|
||||||
|
if (this.authentication.hasPermission(AppPermission.ViewTenantConfigurationPage)) this.adminItems.routes.push({ path: '/tenant-configuration', title: 'SIDE-BAR.TENANT-CONFIGURATION', icon: 'settings' });
|
||||||
if (this.authentication.hasPermission(AppPermission.ViewUserPage)) this.adminItems.routes.push({ path: '/users', title: 'SIDE-BAR.USERS', icon: 'people' });
|
if (this.authentication.hasPermission(AppPermission.ViewUserPage)) this.adminItems.routes.push({ path: '/users', title: 'SIDE-BAR.USERS', icon: 'people' });
|
||||||
if (this.authentication.hasPermission(AppPermission.ViewLanguagePage)) this.adminItems.routes.push({ path: '/languages', title: 'SIDE-BAR.LANGUAGES', icon: 'language' });
|
if (this.authentication.hasPermission(AppPermission.ViewLanguagePage)) this.adminItems.routes.push({ path: '/languages', title: 'SIDE-BAR.LANGUAGES', icon: 'language' });
|
||||||
if (this.authentication.hasPermission(AppPermission.ViewSupportiveMaterialPage)) this.adminItems.routes.push({ path: '/supportive-material', title: 'SIDE-BAR.SUPPORTIVE-MATERIAL', icon: 'help_center' });
|
if (this.authentication.hasPermission(AppPermission.ViewSupportiveMaterialPage)) this.adminItems.routes.push({ path: '/supportive-material', title: 'SIDE-BAR.SUPPORTIVE-MATERIAL', icon: 'help_center' });
|
||||||
|
|
Loading…
Reference in New Issue