Merge branch 'dmp-refactoring' of https://code-repo.d4science.org/MaDgiK-CITE/argos into dmp-refactoring
This commit is contained in:
commit
42a302f77f
|
@ -55,3 +55,4 @@ dmp-backend/web/src/main/resources/certificates/
|
|||
dmp-backend/target/classes/
|
||||
dmp-backend/core/target/maven-archiver/
|
||||
dmp-backend/node_modules/.yarn-integrity
|
||||
dmp-frontend/.nx/
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
package eu.eudat.authorization;
|
||||
|
||||
public final class Permission {
|
||||
/////// Should Remove after Refactor
|
||||
|
||||
public static String AdminRole = "AdminRole";
|
||||
public static String AuthenticatedRole = "AuthenticatedRole";
|
||||
|
||||
/////
|
||||
public static String DeferredAffiliation = "DeferredAffiliation";
|
||||
|
||||
|
@ -222,5 +217,6 @@ public final class Permission {
|
|||
public static String ViewMyDmpPage = "ViewMyDmpPage";
|
||||
public static String ViewHomePage = "ViewHomePage";
|
||||
public static String ViewMineInAppNotificationPage = "ViewMineInAppNotificationPage";
|
||||
public static String ViewTenantConfigurationPage = "ViewTenantConfigurationPage";
|
||||
|
||||
}
|
||||
|
|
|
@ -184,4 +184,14 @@ public class ErrorThesaurusProperties {
|
|||
public void setTenantConfigurationTypeCanNotChange(ErrorDescription 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()))
|
||||
.failOn(TenantConfigurationPersist._cssColors).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._cssColors}, LocaleContextHolder.getLocale())),
|
||||
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()))
|
||||
.failOn(TenantConfigurationPersist._defaultUserLocale).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._defaultUserLocale}, LocaleContextHolder.getLocale())),
|
||||
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()))
|
||||
.failOn(TenantConfigurationPersist._depositPlugins).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._depositPlugins}, LocaleContextHolder.getLocale())),
|
||||
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()))
|
||||
.failOn(TenantConfigurationPersist._fileTransformerPlugins).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantConfigurationPersist._fileTransformerPlugins}, LocaleContextHolder.getLocale())),
|
||||
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()))
|
||||
.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.tenantconfiguration.*;
|
||||
import eu.eudat.model.tenantconfiguration.TenantConfiguration;
|
||||
import eu.eudat.query.TenantConfigurationQuery;
|
||||
import eu.eudat.service.encryption.EncryptionService;
|
||||
import eu.eudat.service.storage.StorageFileService;
|
||||
import eu.eudat.service.tenant.TenantProperties;
|
||||
import gr.cite.commons.web.authz.service.AuthorizationService;
|
||||
import gr.cite.tools.data.builder.BuilderFactory;
|
||||
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.MyForbiddenException;
|
||||
import gr.cite.tools.exception.MyNotFoundException;
|
||||
|
@ -79,6 +81,7 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
|
|||
|
||||
private final TenantProperties tenantProperties;
|
||||
private final StorageFileService storageFileService;
|
||||
private final QueryFactory queryFactory;
|
||||
@Autowired
|
||||
public TenantConfigurationServiceImpl(
|
||||
TenantEntityManager entityManager,
|
||||
|
@ -87,7 +90,7 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
|
|||
BuilderFactory builderFactory,
|
||||
ConventionService conventionService,
|
||||
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.authorizationService = authorizationService;
|
||||
this.deleterFactory = deleterFactory;
|
||||
|
@ -99,6 +102,7 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
|
|||
this.encryptionService = encryptionService;
|
||||
this.tenantProperties = tenantProperties;
|
||||
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 {
|
||||
|
@ -122,7 +126,11 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
|
|||
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()){
|
||||
case CssColors -> data.setValue(this.jsonHandlingService.toJson(this.buildCssColorsTenantConfigurationEntity(model.getCssColors())));
|
||||
case DefaultUserLocale -> data.setValue(this.jsonHandlingService.toJson(this.buildDefaultUserLocaleTenantConfigurationEntity(model.getDefaultUserLocale())));
|
||||
|
|
|
@ -3,6 +3,9 @@ package eu.eudat.controllers;
|
|||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import eu.eudat.audit.AuditableAction;
|
||||
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.model.DescriptionTemplateType;
|
||||
import eu.eudat.model.builder.tenantconfiguration.TenantConfigurationBuilder;
|
||||
|
@ -56,23 +59,25 @@ public class TenantConfigurationController {
|
|||
private final QueryFactory queryFactory;
|
||||
|
||||
private final MessageSource messageSource;
|
||||
private final TenantScope tenantScope;
|
||||
|
||||
public TenantConfigurationController(
|
||||
BuilderFactory builderFactory,
|
||||
AuditService auditService,
|
||||
TenantConfigurationService tenantConfigurationService, CensorFactory censorFactory,
|
||||
QueryFactory queryFactory,
|
||||
MessageSource messageSource) {
|
||||
BuilderFactory builderFactory,
|
||||
AuditService auditService,
|
||||
TenantConfigurationService tenantConfigurationService, CensorFactory censorFactory,
|
||||
QueryFactory queryFactory,
|
||||
MessageSource messageSource, TenantScope tenantScope) {
|
||||
this.builderFactory = builderFactory;
|
||||
this.auditService = auditService;
|
||||
this.tenantConfigurationService = tenantConfigurationService;
|
||||
this.censorFactory = censorFactory;
|
||||
this.queryFactory = queryFactory;
|
||||
this.messageSource = messageSource;
|
||||
this.tenantScope = tenantScope;
|
||||
}
|
||||
|
||||
@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());
|
||||
|
||||
this.censorFactory.censor(TenantConfigurationCensor.class).censor(lookup.getProject(), null);
|
||||
|
@ -89,7 +94,7 @@ public class TenantConfigurationController {
|
|||
}
|
||||
|
||||
@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));
|
||||
|
||||
this.censorFactory.censor(TenantConfigurationCensor.class).censor(fieldSet, null);
|
||||
|
@ -107,10 +112,30 @@ public class TenantConfigurationController {
|
|||
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")
|
||||
@Transactional
|
||||
@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));
|
||||
TenantConfiguration persisted = this.tenantConfigurationService.persist(model, fieldSet);
|
||||
|
||||
|
@ -124,7 +149,7 @@ public class TenantConfigurationController {
|
|||
|
||||
@DeleteMapping("{id}")
|
||||
@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));
|
||||
|
||||
this.tenantConfigurationService.deleteAndSave(id);
|
||||
|
|
|
@ -62,4 +62,7 @@ error-thesaurus:
|
|||
tenant-configuration-type-can-not-change:
|
||||
code: 124
|
||||
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:
|
||||
extendedClaims: [ ]
|
||||
policies:
|
||||
###### Should Remove after Refactor
|
||||
AdminRole:
|
||||
roles:
|
||||
- Admin
|
||||
clients: [ ]
|
||||
allowAnonymous: false
|
||||
allowAuthenticated: false
|
||||
AuthenticatedRole:
|
||||
roles: []
|
||||
clients: [ ]
|
||||
allowAnonymous: false
|
||||
allowAuthenticated: true
|
||||
|
||||
######
|
||||
# Affiliation
|
||||
DeferredAffiliation:
|
||||
roles:
|
||||
|
@ -1027,4 +1013,11 @@ permissions:
|
|||
roles: [ ]
|
||||
clients: [ ]
|
||||
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',
|
||||
loadChildren: () => import('@notification-service/ui/admin/notification/notification.module').then(m => m.NotificationModule),
|
||||
|
|
|
@ -1,75 +1,199 @@
|
|||
export enum AppPermission {
|
||||
//DescriptionTemplateType
|
||||
BrowseDescriptionTemplateType = "BrowseDescriptionTemplateType",
|
||||
EditDescriptionTemplateType = "EditDescriptionTemplateType",
|
||||
DeleteDescriptionTemplateType = "DeleteDescriptionTemplateType",
|
||||
/////
|
||||
DeferredAffiliation = "DeferredAffiliation",
|
||||
|
||||
//DmpBlueprint
|
||||
BrowseDmpBlueprint = "BrowseDmpBlueprint",
|
||||
EditDmpBlueprint = "EditDmpBlueprint",
|
||||
DeleteDmpBlueprint = "DeleteDmpBlueprint",
|
||||
|
||||
//Description
|
||||
BrowseDescription = "BrowseDescription",
|
||||
EditDescription = "EditDescription",
|
||||
FinalizeDescription = "FinalizeDescription",
|
||||
DeleteDescription= "DeleteDescription",
|
||||
|
||||
//Dmp
|
||||
BrowseDmp = "BrowseDmp",
|
||||
EditDmp = "EditDmp",
|
||||
NewDmp = "NewDmp",
|
||||
DeleteDmp = "DeleteDmp",
|
||||
DepositDmp = "DepositDmp",
|
||||
CloneDmp = "CloneDmp",
|
||||
CreateNewVersionDmp = "CreateNewVersionDmp",
|
||||
ExportDmp = "ExportDmp",
|
||||
FinalizeDmp = "FinalizeDmp",
|
||||
AssignDmpUsers = "AssignDmpUsers",
|
||||
InviteDmpUsers = "InviteDmpUsers",
|
||||
|
||||
//DescriptionTemplateType
|
||||
BrowseDescriptionTemplate = "BrowseDescriptionTemplate",
|
||||
EditDescriptionTemplate = "EditDescriptionTemplate",
|
||||
DeleteDescriptionTemplate = "DeleteDescriptionTemplate",
|
||||
//Public
|
||||
PublicBrowseDescription = "PublicBrowseDescription",
|
||||
PublicBrowseDescriptionTemplate = "PublicBrowseDescriptionTemplate",
|
||||
PublicBrowseDmp = "PublicBrowseDmp",
|
||||
PublicBrowseDmpReference = "PublicBrowseDmpReference",
|
||||
PublicBrowseDmpUser = "PublicBrowseDmpUser",
|
||||
PublicBrowseReference = "PublicBrowseReference",
|
||||
PublicBrowseUser = "PublicBrowseUser",
|
||||
PublicBrowseDashboardStatistics = "PublicBrowseDashboardStatistics",
|
||||
PublicSendContactSupport = "PublicSendContactSupport",
|
||||
PublicBrowseReferenceType = "PublicBrowseReferenceType",
|
||||
//Elastic
|
||||
ManageElastic = "ManageElastic",
|
||||
//Queue Events
|
||||
ManageQueueEvents = "ManageQueueEvents",
|
||||
|
||||
|
||||
//ReferenceType
|
||||
BrowseReferenceType = "BrowseReferenceType",
|
||||
EditReferenceType = "EditReferenceType",
|
||||
DeleteReferenceType = "DeleteReferenceType",
|
||||
//Deposit
|
||||
BrowseDeposit = "BrowseDeposit",
|
||||
EditDeposit = "BrowseDeposit",
|
||||
|
||||
//Tenant
|
||||
BrowseTenant = "BrowseTenant",
|
||||
EditTenant = "EditTenant",
|
||||
DeleteTenant = "DeleteTenant",
|
||||
|
||||
//User
|
||||
BrowseUser = "BrowseUser",
|
||||
EditUser = "EditUser",
|
||||
DeleteUser = "DeleteUser",
|
||||
ExportUsers = "ExportUsers",
|
||||
|
||||
//Reference
|
||||
BrowseReference = "BrowseReference",
|
||||
EditReference = "EditReference",
|
||||
DeleteReference = "DeleteReference",
|
||||
|
||||
//Language
|
||||
BrowseLanguage = "BrowseLanguage",
|
||||
EditLanguage = "EditLanguage",
|
||||
DeleteLanguage = "DeleteLanguage",
|
||||
|
||||
//Notification Template
|
||||
|
||||
//NotificationTemplate
|
||||
BrowseNotificationTemplate = "BrowseNotificationTemplate",
|
||||
EditNotificationTemplate = "EditNotificationTemplate",
|
||||
DeleteNotificationTemplate = "DeleteNotificationTemplate",
|
||||
|
||||
//Prefilling Source
|
||||
BrowsePrefillingSource= "BrowsePrefillingSource",
|
||||
EditPrefillingSource = "EditPrefillingSource",
|
||||
//Language
|
||||
BrowseStatistics = "BrowseStatistics",
|
||||
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",
|
||||
|
||||
|
||||
// UI Pages
|
||||
ViewDescriptionTemplateTypePage = "ViewDescriptionTemplateTypePage",
|
||||
ViewMaintenancePage = "ViewMaintenancePage",
|
||||
|
@ -91,5 +215,6 @@ export enum AppPermission {
|
|||
ViewMyDmpPage = "ViewMyDmpPage",
|
||||
ViewHomePage = "ViewHomePage",
|
||||
ViewMineInAppNotificationPage = "ViewMineInAppNotificationPage",
|
||||
ViewTenantConfigurationPage = "ViewTenantConfigurationPage",
|
||||
}
|
||||
|
||||
|
|
|
@ -13,5 +13,8 @@ export enum ResponseErrorCode {
|
|||
DmpBlueprintHasNoDescriptionTemplates = 120,
|
||||
DmpBlueprintNewVersionConflict = 121,
|
||||
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 { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.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.
|
||||
|
@ -110,6 +111,7 @@ export class CoreServiceModule {
|
|||
SemanticsService,
|
||||
PrefillingSourceService,
|
||||
VisibilityRulesService,
|
||||
TenantConfigurationService,
|
||||
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;
|
||||
code?: 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
|
||||
|
@ -39,31 +12,5 @@ export interface TenantPersist extends BaseEntityPersist{
|
|||
name: string;
|
||||
code: 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>
|
||||
<!-- 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>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
|
|
@ -108,10 +108,6 @@ export class TenantEditorComponent extends BaseEditor<TenantEditorModel, Tenant>
|
|||
try {
|
||||
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.buildForm();
|
||||
} catch (error) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
|
||||
import { Tenant, TenantConfig, TenantConfigPersist, TenantDepositConfig, TenantDepositConfigPersist, TenantFileTransformersConfig, TenantFileTransformersConfigPersist, TenantPersist, TenantSource, TenantSourcePersist } from "@app/core/model/tenant/tenant";
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
|
||||
import { Tenant, TenantPersist } from "@app/core/model/tenant/tenant";
|
||||
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";
|
||||
|
@ -9,7 +9,6 @@ export class TenantEditorModel extends BaseEditorModel implements TenantPersist
|
|||
name: string;
|
||||
code: string;
|
||||
description: string;
|
||||
config: TenantConfigEditorModel = new TenantConfigEditorModel();
|
||||
permissions: string[];
|
||||
|
||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
|
||||
|
@ -23,7 +22,6 @@ export class TenantEditorModel extends BaseEditorModel implements TenantPersist
|
|||
this.name = item.name;
|
||||
this.code = item.code;
|
||||
this.description = item.description;
|
||||
if (item.config) this.config = new TenantConfigEditorModel(this.validationErrorModel).fromModel(item.config);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -36,9 +34,6 @@ export class TenantEditorModel extends BaseEditorModel implements TenantPersist
|
|||
name: [{ value: this.name, disabled: disabled }, context.getValidation('name').validators],
|
||||
code: [{ value: this.code, disabled: disabled }, context.getValidation('code').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]
|
||||
});
|
||||
}
|
||||
|
@ -55,301 +50,4 @@ export class TenantEditorModel extends BaseEditorModel implements TenantPersist
|
|||
baseContext.validation = baseValidationArray;
|
||||
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 { 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 { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
|
||||
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.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.updatedAt),
|
||||
|
|
|
@ -14,7 +14,6 @@ import { TenantEditorComponent } from './editor/tenant-editor.component';
|
|||
import { TenantListingComponent } from './listing/tenant-listing.component';
|
||||
import { TenantListingFiltersComponent } from "./listing/filters/tenant-listing-filters.component";
|
||||
import { RichTextEditorModule } from '@app/library/rich-text-editor/rich-text-editor.module';
|
||||
import { TenantSourceComponent } from './editor/source/tenant-source.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
@ -34,8 +33,7 @@ import { TenantSourceComponent } from './editor/source/tenant-source.component';
|
|||
declarations: [
|
||||
TenantEditorComponent,
|
||||
TenantListingComponent,
|
||||
TenantListingFiltersComponent,
|
||||
TenantSourceComponent
|
||||
TenantListingFiltersComponent
|
||||
]
|
||||
})
|
||||
export class TenantModule { }
|
||||
|
|
|
@ -111,8 +111,8 @@
|
|||
<div>{{'DESCRIPTION-EDITOR.TOC.NEXT' | translate}}</div>
|
||||
<span class="material-icons">chevron_right</span>
|
||||
</div>
|
||||
<button [disabled]="saving" (click)="save(saveAnd.addNew)" *ngIf="(step === maxStep) && !isLocked && formGroup.get('descriptionTemplateId').value && !viewOnly" mat-raised-button type="button" class="col-auto stepper-btn add-description-btn ml-auto">
|
||||
{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE-AND-ADD-NEW' | translate }}
|
||||
<button [disabled]="saving" (click)="saveAndClose()" *ngIf="(step === maxStep) && !isLocked && formGroup.get('descriptionTemplateId').value && !viewOnly" mat-raised-button type="button" class="col-auto stepper-btn add-description-btn ml-auto">
|
||||
{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto pr-0">
|
||||
|
|
|
@ -806,6 +806,37 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
}
|
||||
}
|
||||
|
||||
get maxStep() {
|
||||
return this.visibleFieldSets.length;
|
||||
}
|
||||
|
||||
public nextStep() {
|
||||
if (this.step < this.maxStep) {//view is changing
|
||||
this.step = Math.floor(this.step + 1);
|
||||
let entry = this.visibleFieldSets[this.step - 1];
|
||||
this.table0fContents.onToCentrySelected(entry, false);
|
||||
this.scroll(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public previousStep() {
|
||||
if (this.step > 0) {
|
||||
this.step = Math.ceil(this.step - 1);
|
||||
if (this.step >= 1) {
|
||||
let entry = this.visibleFieldSets[this.step - 1];
|
||||
this.table0fContents.onToCentrySelected(entry, false);
|
||||
this.scroll(entry);
|
||||
} else {
|
||||
this.table0fContents.onToCentrySelected(null, false);
|
||||
this.resetScroll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private scroll(entry: ToCEntry) {
|
||||
document.getElementById(entry.id).scrollIntoView();
|
||||
}
|
||||
|
||||
private resetScroll() {
|
||||
document.getElementById('description-editor-form').scrollTop = 0;
|
||||
}
|
||||
|
@ -1968,56 +1999,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// hasNotReversableStatus(): boolean {
|
||||
// if (this.formGroup.get('dmp').value && !this.publicMode) {
|
||||
// return (this.formGroup.get('dmp').value.status == DmpStatus.Finalized && this.formGroup.get('status').value == DescriptionStatus.Finalized);
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// reverse() {
|
||||
|
||||
// this.dialog.open(ConfirmationDialogComponent, {
|
||||
// data: {
|
||||
// message: this.language.instant('DATASET-WIZARD.ACTIONS.UNDO-FINALIZATION-QUESTION'),
|
||||
// confirmButton: this.language.instant('DATASET-WIZARD.ACTIONS.CONFIRM'),
|
||||
// cancelButton: this.language.instant('DATASET-WIZARD.ACTIONS.REJECT'),
|
||||
// },
|
||||
// maxWidth: '30em'
|
||||
// })
|
||||
// .afterClosed()
|
||||
// .pipe(
|
||||
// filter(x => x),
|
||||
// takeUntil(this._destroyed)
|
||||
// ).subscribe(result => {
|
||||
// if (result) {
|
||||
// // if (!this.isFormValid()) { return; }
|
||||
// this.formGroup.get('status').setValue(DescriptionStatus.Draft);
|
||||
// this.submit(SaveType.finalize, () => {
|
||||
// this.viewOnly = false;
|
||||
// this.descriptionModel.status = DescriptionStatus.Draft;
|
||||
// setTimeout(x => {
|
||||
// this.formGroup = null;
|
||||
// });
|
||||
// setTimeout(x => {
|
||||
// this.formGroup = this.descriptionModel.buildForm();
|
||||
// this.registerFormListeners();
|
||||
// });
|
||||
// }, () => {
|
||||
// this.formGroup.get('status').setValue(DescriptionStatus.Finalized);
|
||||
// this.viewOnly = true;
|
||||
// });
|
||||
// } else {
|
||||
// this.saving = false;
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
// }
|
||||
|
||||
// saveFinalize() {
|
||||
// // this.formService.touchAllFormFields(this.formGroup);
|
||||
// this.saving = true;
|
||||
|
@ -2125,43 +2106,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
// });
|
||||
// }
|
||||
|
||||
// downloadPDF(id: string): void {
|
||||
// this.descriptionService.downloadPDF(id)
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(response => {
|
||||
// const blob = new Blob([response.body], { type: 'application/pdf' });
|
||||
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
|
||||
|
||||
// FileSaver.saveAs(blob, filename);
|
||||
// this.matomoService.trackDownload('descriptions', "pdf", id);
|
||||
// });
|
||||
// }
|
||||
|
||||
// downloadDOCX(id: string): void {
|
||||
// this.descriptionService.downloadDOCX(id)
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(response => {
|
||||
// const blob = new Blob([response.body], { type: 'application/msword' });
|
||||
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
|
||||
|
||||
// FileSaver.saveAs(blob, filename);
|
||||
// this.matomoService.trackDownload('descriptions', "docx", id);
|
||||
// });
|
||||
|
||||
// }
|
||||
|
||||
// downloadXML(id: string): void {
|
||||
// this.descriptionService.downloadXML(id)
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(response => {
|
||||
// const blob = new Blob([response.body], { type: 'application/xml' });
|
||||
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
|
||||
|
||||
// FileSaver.saveAs(blob, filename);
|
||||
// this.matomoService.trackDownload('descriptions', "xml", id);
|
||||
// });
|
||||
// }
|
||||
|
||||
// // advancedClicked() {
|
||||
// // const dialogRef = this.dialog.open(ExportMethodDialogComponent, {
|
||||
// // maxWidth: '500px',
|
||||
|
@ -2326,53 +2270,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
// }
|
||||
// }
|
||||
|
||||
// public changeStep(selected: ToCEntry = null, execute: boolean = true) {
|
||||
// if (execute) {
|
||||
// if (selected) {
|
||||
// let fieldSet = this.getFirstFieldSet(selected);
|
||||
// let index = this.visibleFieldSets.findIndex(entry => entry.id === fieldSet.id);
|
||||
// this.step = index + (selected.type === ToCEntryType.FieldSet ? 1 : 0.5);
|
||||
// } else {
|
||||
// this.step = 0;
|
||||
// this.resetScroll();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// get maxStep() {
|
||||
// return this.visibleFieldSets.length;
|
||||
// }
|
||||
|
||||
// public nextStep() {
|
||||
// if (this.step < this.maxStep) {//view is changing
|
||||
// this.step = Math.floor(this.step + 1);
|
||||
// let entry = this.visibleFieldSets[this.step - 1];
|
||||
// this.table0fContents.onToCentrySelected(entry, false);
|
||||
// this.scroll(entry);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public previousStep() {
|
||||
// if (this.step > 0) {
|
||||
// this.step = Math.ceil(this.step - 1);
|
||||
// if (this.step >= 1) {
|
||||
// let entry = this.visibleFieldSets[this.step - 1];
|
||||
// this.table0fContents.onToCentrySelected(entry, false);
|
||||
// this.scroll(entry);
|
||||
// } else {
|
||||
// this.table0fContents.onToCentrySelected(null, false);
|
||||
// this.resetScroll();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// private resetScroll() {
|
||||
// document.getElementById('description-editor-form').scrollTop = 0;
|
||||
// }
|
||||
|
||||
// private scroll(entry: ToCEntry) {
|
||||
// document.getElementById(entry.id).scrollIntoView();
|
||||
// }
|
||||
|
||||
// isDirty() {
|
||||
// return this.formGroup.dirty && this.hasChanges; // do we need this.formGroup.dirty
|
||||
|
@ -2411,11 +2308,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
// this.location.go(url);
|
||||
// }
|
||||
|
||||
// backToDmp(id: string) {
|
||||
// this.router.navigate(['/plans', 'edit', id]);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// getLinks(currentLinks: Link[]) {
|
||||
// this.links = currentLinks;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div *ngIf="!fieldSet?.multiplicity?.tableView" class="col-12">
|
||||
<div class="row" *ngFor="let fieldSetItemPropertiesControl of propertiesFormGroup?.get('items')?.controls">
|
||||
<div class="row" *ngFor="let fieldSetItemPropertiesControl of propertiesFormGroup?.get('items')?.controls; let i=index;">
|
||||
<div class="col" *ngIf="visibilityRulesService && visibilityRulesService.isVisibleMap[fieldSet.id + '_' + fieldSetItemPropertiesControl.get('ordinal').value] ?? true">
|
||||
<div class="row">
|
||||
<div *ngFor="let field of fieldSet.fields; let i = index;" class="col-12">
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
</ng-container>
|
||||
<ng-container *ngSwitchCase="descriptionTemplateFieldTypeEnum.UPLOAD">
|
||||
<div class="col-12 d-flex justify-content-center">
|
||||
<ngx-dropzone class="drop-file col-12" (change)="fileChangeEvent($event, true)" [multiple]="false" [accept]="typesToString()" [disabled]="propertiesFormGroup?.get(field.id).get('textValue').disabled">
|
||||
<ngx-dropzone #drop class="drop-file col-12" (change)="fileChangeEvent($event, true)" [multiple]="false" [accept]="typesToString()" [disabled]="propertiesFormGroup?.get(field.id).get('textValue').disabled">
|
||||
<ngx-dropzone-preview *ngIf="propertiesFormGroup?.get(field.id).get('textValue').value" class="file-preview" [removable]="true" (removed)="onRemove()">
|
||||
<ngx-dropzone-label class="file-label">{{ fileNameDisplay }}</ngx-dropzone-label>
|
||||
</ngx-dropzone-preview>
|
||||
|
|
|
@ -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.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.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.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' });
|
||||
|
|
Loading…
Reference in New Issue