From 7bb85bb3e9ac081f8480a90a415b85a43372d15e Mon Sep 17 00:00:00 2001 From: ThuF Date: Thu, 21 May 2026 18:42:59 +0300 Subject: [PATCH 1/5] [EDM] Add Java Templates --- .gitignore | 2 +- components/group/group-templates/pom.xml | 8 + components/pom.xml | 12 + .../application-core/styles/fonts.css | 11 + .../template-application-dao-java/pom.xml | 24 ++ .../data/Entity.java.template | 45 +++ .../data/Repository.java.template | 12 + .../data/entity.extensionpoint.template | 4 + .../project.json | 5 + .../project.json.mjs | 22 ++ .../template/template.extension | 5 + .../template/template.js | 65 ++++ .../template-application-rest-java/pom.xml | 24 ++ .../api/EntityController.java.template | 94 ++++++ .../project.json | 9 + .../project.json.mjs | 22 ++ .../roles/default-roles.roles.template | 15 + .../template/template.extension | 5 + .../template/template.js | 52 ++++ .../template/parameterUtils.js | 58 +++- .../integration/tests/api/JavaTemplateIT.java | 279 ++++++++++++++++++ 21 files changed, 771 insertions(+), 2 deletions(-) create mode 100644 components/template/template-application-dao-java/pom.xml create mode 100644 components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Entity.java.template create mode 100644 components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Repository.java.template create mode 100644 components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/entity.extensionpoint.template create mode 100644 components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/project.json create mode 100644 components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/project.json.mjs create mode 100644 components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/template/template.extension create mode 100644 components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/template/template.js create mode 100644 components/template/template-application-rest-java/pom.xml create mode 100644 components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template create mode 100644 components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/project.json create mode 100644 components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/project.json.mjs create mode 100644 components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/roles/default-roles.roles.template create mode 100644 components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/template/template.extension create mode 100644 components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/template/template.js create mode 100644 tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java diff --git a/.gitignore b/.gitignore index 0494531c456..a4c6fb9badf 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,4 @@ package-lock.json **/ttyd.sh **/spring-shell.log **/version.txt -/.claude/scheduled_tasks.lock +.claude/ diff --git a/components/group/group-templates/pom.xml b/components/group/group-templates/pom.xml index 7baca06c604..1695d6bfbf6 100644 --- a/components/group/group-templates/pom.xml +++ b/components/group/group-templates/pom.xml @@ -27,6 +27,10 @@ org.eclipse.dirigible dirigible-components-template-application-dao + + org.eclipse.dirigible + dirigible-components-template-application-dao-java + org.eclipse.dirigible dirigible-components-template-application-dao-v2 @@ -55,6 +59,10 @@ org.eclipse.dirigible dirigible-components-template-application-rest + + org.eclipse.dirigible + dirigible-components-template-application-rest-java + org.eclipse.dirigible dirigible-components-template-application-rest-v2 diff --git a/components/pom.xml b/components/pom.xml index 1469682af16..bab1070f9af 100644 --- a/components/pom.xml +++ b/components/pom.xml @@ -239,6 +239,7 @@ template/template-application-angular template/template-application-angular-v2 template/template-application-dao + template/template-application-dao-java template/template-application-dao-v2 template/template-application-data template/template-application-data-v2 @@ -246,6 +247,7 @@ template/template-application-feed-v2 template/template-application-odata template/template-application-rest + template/template-application-rest-java template/template-application-rest-v2 template/template-application-schema template/template-application-ui-angular @@ -1370,6 +1372,11 @@ dirigible-components-template-application-dao ${project.version} + + org.eclipse.dirigible + dirigible-components-template-application-dao-java + ${project.version} + org.eclipse.dirigible dirigible-components-template-application-dao-v2 @@ -1405,6 +1412,11 @@ dirigible-components-template-application-rest ${project.version} + + org.eclipse.dirigible + dirigible-components-template-application-rest-java + ${project.version} + org.eclipse.dirigible dirigible-components-template-application-rest-v2 diff --git a/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/styles/fonts.css b/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/styles/fonts.css index 3c4c348820e..15ec7c1a831 100644 --- a/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/styles/fonts.css +++ b/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/styles/fonts.css @@ -1,3 +1,14 @@ +/** + * Copyright (c) 2010-2026 Eclipse Dirigible contributors + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * SPDX-FileCopyrightText: Eclipse Dirigible contributors + * SPDX-License-Identifier: EPL-2.0 + */ /* open-sans-latin-300-normal */ @font-face { font-family: "Open Sans"; diff --git a/components/template/template-application-dao-java/pom.xml b/components/template/template-application-dao-java/pom.xml new file mode 100644 index 00000000000..03acb105c21 --- /dev/null +++ b/components/template/template-application-dao-java/pom.xml @@ -0,0 +1,24 @@ + + 4.0.0 + + + org.eclipse.dirigible + dirigible-components-parent + 13.0.0-SNAPSHOT + ../../pom.xml + + + Components - Template - Application - DAO - Java + dirigible-components-template-application-dao-java + jar + + + generate-sources + template-application-dao-java + template-application-dao-java + + ../generation-header.txt + + + diff --git a/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Entity.java.template b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Entity.java.template new file mode 100644 index 00000000000..b9ccd163d46 --- /dev/null +++ b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Entity.java.template @@ -0,0 +1,45 @@ +package gen.${javaGenFolderName}.data.${javaPerspectiveName}; + +import org.eclipse.dirigible.engine.java.annotations.Column; +import org.eclipse.dirigible.engine.java.annotations.CreatedAt; +import org.eclipse.dirigible.engine.java.annotations.CreatedBy; +import org.eclipse.dirigible.engine.java.annotations.Documentation; +import org.eclipse.dirigible.engine.java.annotations.Entity; +import org.eclipse.dirigible.engine.java.annotations.GeneratedValue; +import org.eclipse.dirigible.engine.java.annotations.GenerationType; +import org.eclipse.dirigible.engine.java.annotations.Id; +import org.eclipse.dirigible.engine.java.annotations.Table; +import org.eclipse.dirigible.engine.java.annotations.UpdatedAt; +import org.eclipse.dirigible.engine.java.annotations.UpdatedBy; + +@Entity +@Table(name = "${tablePrefix}${dataName}") +@Documentation("${name} entity mapping") +public class ${name}Entity { + +#foreach($property in $properties) +#if($property.dataPrimaryKey) + @Id +#end +#if($property.dataAutoIncrement) + @GeneratedValue(strategy = GenerationType.IDENTITY) +#end +#if($property.auditType == "CREATED_AT") + @CreatedAt +#elseif($property.auditType == "CREATED_BY") + @CreatedBy +#elseif($property.auditType == "UPDATED_AT") + @UpdatedAt +#elseif($property.auditType == "UPDATED_BY") + @UpdatedBy +#end + @Column(name = "${property.dataName}"#if($property.dataLength && $property.dataType != "DECIMAL"), length = ${property.dataLength}#end#if($property.dataPrecision), precision = ${property.dataPrecision}#end#if($property.dataScale), scale = ${property.dataScale}#end#if(!$property.dataPrimaryKey && $property.dataNotNull), nullable = false#elseif(!$property.dataPrimaryKey && !$property.dataNotNull), nullable = true#end#if($property.dataUnique), unique = true#end) +#if($property.description) + @Documentation("${property.description}") +#else + @Documentation("${property.name}") +#end + public ${property.dataTypeJavaClass} ${property.name}; + +#end +} diff --git a/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Repository.java.template b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Repository.java.template new file mode 100644 index 00000000000..e07c66dbbbf --- /dev/null +++ b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Repository.java.template @@ -0,0 +1,12 @@ +package gen.${javaGenFolderName}.data.${javaPerspectiveName}; + +import org.eclipse.dirigible.components.data.store.java.repository.JavaRepository; +import org.eclipse.dirigible.engine.java.annotations.Repository; + +@Repository +public class ${name}Repository extends JavaRepository<${name}Entity> { + + public ${name}Repository() { + super(${name}Entity.class); + } +} diff --git a/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/entity.extensionpoint.template b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/entity.extensionpoint.template new file mode 100644 index 00000000000..c6aec60938d --- /dev/null +++ b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/entity.extensionpoint.template @@ -0,0 +1,4 @@ +{ + "name": "${projectName}-${perspectiveName}-${name}", + "description": "Extension Point for the ${projectName}-${perspectiveName}-${name} entity" +} diff --git a/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/project.json b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/project.json new file mode 100644 index 00000000000..f786d00d734 --- /dev/null +++ b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/project.json @@ -0,0 +1,5 @@ +{ + "guid": "template-application-dao-java", + "dependencies": [], + "actions": [] +} diff --git a/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/project.json.mjs b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/project.json.mjs new file mode 100644 index 00000000000..ec680a2377d --- /dev/null +++ b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/project.json.mjs @@ -0,0 +1,22 @@ +import { workspace } from '@aerokit/sdk/platform'; + +export function generate(json) { + const parameters = JSON.parse(json); + + const newProjectFile = JSON.stringify({ + 'guid': parameters.projectName + }); + + const currenctWorkspace = workspace.getWorkspace(parameters.workspaceName); + const currentProject = currenctWorkspace.getProject(parameters.projectName); + const maybeProjectFile = currentProject.getFile('project.json'); + + if (maybeProjectFile.exists()) { + const projectFileContent = maybeProjectFile.getText(); + if (projectFileContent.trim() !== '') { + return projectFileContent; + } + } + + return newProjectFile; +} diff --git a/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/template/template.extension b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/template/template.extension new file mode 100644 index 00000000000..23d636a32c5 --- /dev/null +++ b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/template/template.extension @@ -0,0 +1,5 @@ +{ + "module": "template-application-dao-java/template/template.js", + "extensionPoint": "platform-templates", + "description": "Application Template - DAO - Java" +} diff --git a/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/template/template.js b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/template/template.js new file mode 100644 index 00000000000..d80bf882f2a --- /dev/null +++ b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/template/template.js @@ -0,0 +1,65 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +import * as generateUtils from "service-generate/template/generateUtils"; +import * as parameterUtils from "service-generate/template/parameterUtils"; + +export function generate(model, parameters) { + model = JSON.parse(model).model; + let templateSources = getTemplate(parameters).sources; + parameterUtils.process(model, parameters) + return generateUtils.generateFiles(model, parameters, templateSources); +}; + +export function getTemplate(parameters) { + return { + name: "Application - DAO - Java", + description: "Application with DAO (Java)", + extension: "model", + sources: [ + { + location: "/template-application-dao-java/data/Repository.java.template", + action: "generate", + rename: "gen/{{javaGenFolderName}}/data/{{javaPerspectiveName}}/{{name}}Repository.java", + engine: "velocity", + collection: "daoModels" + }, + { + location: "/template-application-dao-java/data/Entity.java.template", + action: "generate", + rename: "gen/{{javaGenFolderName}}/data/{{javaPerspectiveName}}/{{name}}Entity.java", + engine: "velocity", + collection: "daoModels" + }, + { + location: "/template-application-dao-java/data/entity.extensionpoint.template", + action: "generate", + rename: "gen/{{javaGenFolderName}}/data/{{javaPerspectiveName}}/{{name}}.extensionpoint", + engine: "velocity", + collection: "daoModels" + }, + { + location: "/template-application-dao-java/project.json.mjs", + action: "generate", + rename: "project.json", + engine: "javascript", + } + ], + parameters: [ + { + name: "tablePrefix", + label: "Table Prefix", + placeholder: "Table prefix", + required: false + }, + { + name: "dataSource", + label: "Data Source", + placeholder: "Data Source (DefaultDB)", + required: false + } + ] + }; +}; diff --git a/components/template/template-application-rest-java/pom.xml b/components/template/template-application-rest-java/pom.xml new file mode 100644 index 00000000000..4d76a26079d --- /dev/null +++ b/components/template/template-application-rest-java/pom.xml @@ -0,0 +1,24 @@ + + 4.0.0 + + + org.eclipse.dirigible + dirigible-components-parent + 13.0.0-SNAPSHOT + ../../pom.xml + + + Components - Template - Application - REST - Java + dirigible-components-template-application-rest-java + jar + + + generate-sources + template-application-rest-java + template-application-rest-java + + ../generation-header.txt + + + diff --git a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template new file mode 100644 index 00000000000..a9a213ad73e --- /dev/null +++ b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template @@ -0,0 +1,94 @@ +package gen.${javaGenFolderName}.api.${javaPerspectiveName}; + +import gen.${javaGenFolderName}.data.${javaPerspectiveName}.${name}Entity; +import gen.${javaGenFolderName}.data.${javaPerspectiveName}.${name}Repository; + +import org.eclipse.dirigible.engine.java.annotations.Documentation; +import org.eclipse.dirigible.engine.java.annotations.Inject; +import org.eclipse.dirigible.engine.java.annotations.http.Body; +import org.eclipse.dirigible.engine.java.annotations.http.Controller; +import org.eclipse.dirigible.engine.java.annotations.http.Delete; +import org.eclipse.dirigible.engine.java.annotations.http.Get; +import org.eclipse.dirigible.engine.java.annotations.http.PathParam; +import org.eclipse.dirigible.engine.java.annotations.http.Post; +import org.eclipse.dirigible.engine.java.annotations.http.Put; +import org.eclipse.dirigible.engine.java.annotations.http.QueryParam; +import org.springframework.http.HttpStatus; +import org.springframework.web.server.ResponseStatusException; + +import java.util.List; +import java.util.Map; + +@Controller +@Documentation("${projectName} - ${name} Controller") +public class ${name}Controller { + + @Inject + private ${name}Repository repository; + + @Get + @Documentation("List ${name}") + public List<${name}Entity> getAll(@QueryParam("$limit") Integer limit, + @QueryParam("$offset") Integer offset) { + int actualLimit = limit != null ? limit.intValue() : 20; + int actualOffset = offset != null ? offset.intValue() : 0; + return repository.findAll(actualLimit, actualOffset); + } + + @Get("/count") + @Documentation("Count ${name}") + public Map count() { + return Map.of("count", repository.count()); + } + + @Get("/{id}") + @Documentation("Get ${name} by id") + public ${name}Entity getById(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id) { + return repository.findOne(id) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "${name} not found")); + } + + @Post + @Documentation("Create ${name}") + public ${name}Entity create(@Body ${name}Entity entity) { + validate(entity); + return repository.save(entity); + } + + @Put("/{id}") + @Documentation("Update ${name} by id") + public ${name}Entity update(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id, @Body ${name}Entity entity) { + entity.#foreach($property in $properties)#if($property.dataPrimaryKey)${property.name}#end#end = id; + validate(entity); + return repository.update(entity); + } + + @Delete("/{id}") + @Documentation("Delete ${name} by id") + public void deleteById(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id) { + if (repository.findOne(id).isEmpty()) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "${name} not found"); + } + repository.deleteById(id); + } + + private static void validate(${name}Entity entity) { +#foreach($property in $properties) +#if($property.isRequiredProperty) + if (entity.${property.name} == null) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The '${property.name}' property is required"); + } +#end +#if($property.dataTypeJavaClass == "String" && $property.dataLength && $property.dataTypeJava != "time") + if (entity.${property.name} != null && entity.${property.name}.length() > ${property.dataLength}) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The '${property.name}' exceeds the maximum length of ${property.dataLength}"); + } +#end +#if($property.widgetPattern && $property.widgetPattern != "") + if (entity.${property.name} != null && !entity.${property.name}.toString().matches("${property.widgetPattern}")) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The value of '${property.name}' does not match the required pattern '${property.widgetPattern}'"); + } +#end +#end + } +} diff --git a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/project.json b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/project.json new file mode 100644 index 00000000000..1c29d0502fe --- /dev/null +++ b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/project.json @@ -0,0 +1,9 @@ +{ + "guid": "template-application-rest-java", + "dependencies": [ + { + "guid": "template-application-dao-java" + } + ], + "actions": [] +} diff --git a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/project.json.mjs b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/project.json.mjs new file mode 100644 index 00000000000..ec680a2377d --- /dev/null +++ b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/project.json.mjs @@ -0,0 +1,22 @@ +import { workspace } from '@aerokit/sdk/platform'; + +export function generate(json) { + const parameters = JSON.parse(json); + + const newProjectFile = JSON.stringify({ + 'guid': parameters.projectName + }); + + const currenctWorkspace = workspace.getWorkspace(parameters.workspaceName); + const currentProject = currenctWorkspace.getProject(parameters.projectName); + const maybeProjectFile = currentProject.getFile('project.json'); + + if (maybeProjectFile.exists()) { + const projectFileContent = maybeProjectFile.getText(); + if (projectFileContent.trim() !== '') { + return projectFileContent; + } + } + + return newProjectFile; +} diff --git a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/roles/default-roles.roles.template b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/roles/default-roles.roles.template new file mode 100644 index 00000000000..86b292c9fe8 --- /dev/null +++ b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/roles/default-roles.roles.template @@ -0,0 +1,15 @@ +[ +#foreach($role in $roles) + #if($role.roleRead) + { + "name": "${role.roleRead}", + "description": "A role that grants read only permission for ${role.entityName}." + }#end#if($role.roleRead && $role.roleWrite || $foreach.hasNext),#end + #if($role.roleWrite) + { + "name": "${role.roleWrite}", + "description": "A role that grants full access for ${role.entityName}." + }#if($foreach.hasNext),#end + #end +#end +] diff --git a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/template/template.extension b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/template/template.extension new file mode 100644 index 00000000000..b86c1a495ec --- /dev/null +++ b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/template/template.extension @@ -0,0 +1,5 @@ +{ + "module": "template-application-rest-java/template/template.js", + "extensionPoint": "platform-templates", + "description": "Application Template - REST - Java" +} diff --git a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/template/template.js b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/template/template.js new file mode 100644 index 00000000000..0a45006dde1 --- /dev/null +++ b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/template/template.js @@ -0,0 +1,52 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +import * as daoTemplateManager from "template-application-dao-java/template/template"; +import * as generateUtils from "service-generate/template/generateUtils"; +import * as parameterUtils from "service-generate/template/parameterUtils"; + +export function generate(model, parameters) { + model = JSON.parse(model).model; + const templateSources = getTemplate(parameters).sources; + parameterUtils.process(model, parameters) + return generateUtils.generateFiles(model, parameters, templateSources); +}; + +export function getTemplate(parameters) { + const daoTemplate = daoTemplateManager.getTemplate(parameters); + + let templateSources = [{ + location: "/template-application-rest-java/api/EntityController.java.template", + action: "generate", + rename: "gen/{{javaGenFolderName}}/api/{{javaPerspectiveName}}/{{name}}Controller.java", + engine: "velocity", + collection: "apiModels" + }, { + location: "/template-application-rest-java/project.json.mjs", + action: "generate", + rename: "project.json", + engine: "javascript" + }]; + + templateSources.push({ + location: "/template-application-rest-java/roles/default-roles.roles.template", + action: "generate", + engine: "velocity", + rename: "gen/{{javaGenFolderName}}/roles/default-roles.roles" + }); + + templateSources = templateSources.concat(daoTemplate.sources); + + let templateParameters = []; + templateParameters = templateParameters.concat(daoTemplate.parameters); + + return { + name: "Application - REST - Java", + description: "Application with REST APIs (Java)", + extension: "model", + sources: templateSources, + parameters: templateParameters + }; +}; diff --git a/components/ui/service-generate/src/main/resources/META-INF/dirigible/service-generate/template/parameterUtils.js b/components/ui/service-generate/src/main/resources/META-INF/dirigible/service-generate/template/parameterUtils.js index 0f8089765da..3f17216602d 100644 --- a/components/ui/service-generate/src/main/resources/META-INF/dirigible/service-generate/template/parameterUtils.js +++ b/components/ui/service-generate/src/main/resources/META-INF/dirigible/service-generate/template/parameterUtils.js @@ -14,6 +14,8 @@ import { Base64 } from "@aerokit/sdk/utils"; import { Bytes } from "@aerokit/sdk/io"; export function process(model, parameters) { + parameters.javaGenFolderName = sanitizeJavaIdentifier(parameters.genFolderName); + model.entities.forEach(e => { if (parameters.dataSource && !e.dataSource) { e.dataSource = parameters.dataSource; @@ -22,6 +24,7 @@ export function process(model, parameters) { e.dataSource = defaultDataSourceName; parameters.dataSource = defaultDataSourceName; } + e.javaPerspectiveName = sanitizeJavaIdentifier(e.perspectiveName); let tablePrefix = parameters.tablePrefix ? parameters.tablePrefix : ''; if (tablePrefix !== '' && !tablePrefix.endsWith("_")) { tablePrefix = `${tablePrefix}_`; @@ -74,6 +77,7 @@ export function process(model, parameters) { const parsedDataType = parseDataTypes(p.dataType); p.dataTypeJava = parsedDataType.java; p.dataTypeTypescript = parsedDataType.ts; + p.dataTypeJavaClass = resolveJavaClass(parsedDataType.javaClass, p.auditType); if (p.dataPrimaryKey) { if (e.primaryKeys === undefined) { @@ -222,7 +226,8 @@ export function getUniqueParameters(...parameters) { export function parseDataTypes(dataType) { const parsedDataType = { java: '', - ts: '' + ts: '', + javaClass: 'Object' }; switch (dataType.toUpperCase()) { case "TINYINT": @@ -232,6 +237,7 @@ export function parseDataTypes(dataType) { case "SMALLSERIAL": parsedDataType.java = "short"; parsedDataType.ts = "number"; + parsedDataType.javaClass = "Short"; break; case "MEDIUMINT": case "INT3": @@ -241,27 +247,35 @@ export function parseDataTypes(dataType) { case "SERIAL": parsedDataType.java = "int"; parsedDataType.ts = "number"; + parsedDataType.javaClass = "Integer"; break; case "BIGINT": case "INT8": case "BIGSERIAL": parsedDataType.java = "long"; parsedDataType.ts = "number"; + parsedDataType.javaClass = "Long"; break; case "DECIMAL": case "DEC": case "NUMERIC": case "FIXED": + parsedDataType.java = "double"; + parsedDataType.ts = "number"; + parsedDataType.javaClass = "java.math.BigDecimal"; + break; case "DOUBLE": case "DOUBLE PRECISION": case "REAL": parsedDataType.java = "double"; parsedDataType.ts = "number"; + parsedDataType.javaClass = "Double"; break; case "FLOAT": case "MONEY": parsedDataType.java = "float"; parsedDataType.ts = "number"; + parsedDataType.javaClass = "Float"; break; case "CHAR": case "ENUM": @@ -276,36 +290,78 @@ export function parseDataTypes(dataType) { case "CHARACTER VARYING": case "CHARACTER": case "BPCHAR": + case "CLOB": parsedDataType.java = "string"; parsedDataType.ts = "string"; + parsedDataType.javaClass = "String"; break; case "DATE": parsedDataType.java = "date"; parsedDataType.ts = "Date"; + parsedDataType.javaClass = "java.time.LocalDate"; break; case "TIME": case "TIME WITH TIME ZONE": parsedDataType.java = "time"; parsedDataType.ts = "string"; + parsedDataType.javaClass = "java.time.LocalTime"; break; case "DATETIME": case "TIMESTAMP": case "TIMESTAMP WITH TIME ZONE": parsedDataType.java = "timestamp"; parsedDataType.ts = "Date"; + parsedDataType.javaClass = "java.time.Instant"; break; case "BOOLEAN": case "BIT": parsedDataType.java = "boolean"; parsedDataType.ts = "boolean"; + parsedDataType.javaClass = "Boolean"; + break; + case "BLOB": + parsedDataType.java = "blob"; + parsedDataType.ts = "string"; + parsedDataType.javaClass = "byte[]"; break; case "NULL": parsedDataType.java = "null"; parsedDataType.ts = "null"; + parsedDataType.javaClass = "Object"; break; default: parsedDataType.ts = "unknown"; + parsedDataType.javaClass = "Object"; } return parsedDataType; } + +/** + * Resolves the Java class name to emit for a property, applying the audit-field overrides demanded + * by org.eclipse.dirigible.engine.java.annotations.{CreatedAt,UpdatedAt,CreatedBy,UpdatedBy}. + */ +export function resolveJavaClass(baseJavaClass, auditType) { + if (auditType === "CREATED_AT" || auditType === "UPDATED_AT") { + return "java.time.Instant"; + } + if (auditType === "CREATED_BY" || auditType === "UPDATED_BY") { + return "String"; + } + return baseJavaClass || "Object"; +} + +/** + * Sanitises an arbitrary name (perspective, model folder) into a lower-case Java identifier safe + * for use both as a path segment and a package fragment. + */ +export function sanitizeJavaIdentifier(name) { + if (name === undefined || name === null || name === "") { + return "_"; + } + let s = String(name).toLowerCase().replace(/[^a-z0-9_]/g, '_'); + if (/^[0-9]/.test(s)) { + s = '_' + s; + } + return s === "" ? "_" : s; +} diff --git a/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java new file mode 100644 index 00000000000..3861790f317 --- /dev/null +++ b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2010-2026 Eclipse Dirigible contributors + * + * All rights reserved. This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * SPDX-FileCopyrightText: Eclipse Dirigible contributors SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.dirigible.integration.tests.api; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.containsString; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.dirigible.components.initializers.synchronizer.SynchronizationProcessor; +import org.eclipse.dirigible.repository.api.IRepository; +import org.eclipse.dirigible.repository.api.IRepositoryStructure; +import org.eclipse.dirigible.tests.base.IntegrationTest; +import org.eclipse.dirigible.tests.framework.restassured.RestAssuredExecutor; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import io.restassured.http.ContentType; + +/** + * Validates the runtime contract produced by {@code template-application-dao-java} + + * {@code template-application-rest-java}: drops {@code .java} sources matching the templates' + * output (entity + repository + controller) into the registry, triggers synchronization, and + * exercises the generated CRUD endpoints through HTTP. + * + *

+ * The generator step itself runs in JavaScript inside the IDE's template engine and is not invoked + * from this test — that would require the IDE / Selenide. Instead we assert that the *shape of + * code* the templates emit compiles cleanly under {@code engine-java} and reaches the + * {@code /services/java/...} dispatch path the same way {@code JavaEngineIT} does. + */ +class JavaTemplateIT extends IntegrationTest { + + private static final String PROJECT = "java-template-it"; + + private static final String ENTITY_PATH = + IRepositoryStructure.PATH_REGISTRY_PUBLIC + "/" + PROJECT + "/gen/sample/data/books/BookEntity.java"; + private static final String REPOSITORY_PATH = + IRepositoryStructure.PATH_REGISTRY_PUBLIC + "/" + PROJECT + "/gen/sample/data/books/BookRepository.java"; + private static final String CONTROLLER_PATH = + IRepositoryStructure.PATH_REGISTRY_PUBLIC + "/" + PROJECT + "/gen/sample/api/books/BookController.java"; + + private static final String CONTROLLER_BASE = "/services/java/" + PROJECT + "/gen/sample/api/books/BookController"; + + private static final long ASSERTION_TIMEOUT_SECONDS = 30; + + private static final String ENTITY_SOURCE = """ + package gen.sample.data.books; + + import org.eclipse.dirigible.engine.java.annotations.Column; + import org.eclipse.dirigible.engine.java.annotations.Documentation; + import org.eclipse.dirigible.engine.java.annotations.Entity; + import org.eclipse.dirigible.engine.java.annotations.GeneratedValue; + import org.eclipse.dirigible.engine.java.annotations.GenerationType; + import org.eclipse.dirigible.engine.java.annotations.Id; + import org.eclipse.dirigible.engine.java.annotations.Table; + + @Entity + @Table(name = "JAVATEMPLATEIT_BOOK") + @Documentation("Book entity mapping") + public class BookEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "BOOK_ID") + @Documentation("Id") + public Integer id; + + @Column(name = "BOOK_TITLE", length = 40, nullable = false) + @Documentation("Title") + public String title; + } + """; + + private static final String REPOSITORY_SOURCE = """ + package gen.sample.data.books; + + import org.eclipse.dirigible.components.data.store.java.repository.JavaRepository; + import org.eclipse.dirigible.engine.java.annotations.Repository; + + @Repository + public class BookRepository extends JavaRepository { + + public BookRepository() { + super(BookEntity.class); + } + } + """; + + private static final String CONTROLLER_SOURCE = """ + package gen.sample.api.books; + + import gen.sample.data.books.BookEntity; + import gen.sample.data.books.BookRepository; + + import org.eclipse.dirigible.engine.java.annotations.Documentation; + import org.eclipse.dirigible.engine.java.annotations.Inject; + import org.eclipse.dirigible.engine.java.annotations.http.Body; + import org.eclipse.dirigible.engine.java.annotations.http.Controller; + import org.eclipse.dirigible.engine.java.annotations.http.Delete; + import org.eclipse.dirigible.engine.java.annotations.http.Get; + import org.eclipse.dirigible.engine.java.annotations.http.PathParam; + import org.eclipse.dirigible.engine.java.annotations.http.Post; + import org.eclipse.dirigible.engine.java.annotations.http.Put; + import org.eclipse.dirigible.engine.java.annotations.http.QueryParam; + import org.springframework.http.HttpStatus; + import org.springframework.web.server.ResponseStatusException; + + import java.util.List; + import java.util.Map; + + @Controller + @Documentation("java-template-it - Book Controller") + public class BookController { + + @Inject + private BookRepository repository; + + @Get + @Documentation("List Book") + public List getAll(@QueryParam("$limit") Integer limit, + @QueryParam("$offset") Integer offset) { + int actualLimit = limit != null ? limit.intValue() : 20; + int actualOffset = offset != null ? offset.intValue() : 0; + return repository.findAll(actualLimit, actualOffset); + } + + @Get("/count") + @Documentation("Count Book") + public Map count() { + return Map.of("count", repository.count()); + } + + @Get("/{id}") + @Documentation("Get Book by id") + public BookEntity getById(@PathParam("id") Integer id) { + return repository.findOne(id) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Book not found")); + } + + @Post + @Documentation("Create Book") + public BookEntity create(@Body BookEntity entity) { + return repository.save(entity); + } + + @Put("/{id}") + @Documentation("Update Book by id") + public BookEntity update(@PathParam("id") Integer id, @Body BookEntity entity) { + entity.id = id; + return repository.update(entity); + } + + @Delete("/{id}") + @Documentation("Delete Book by id") + public void deleteById(@PathParam("id") Integer id) { + if (repository.findOne(id).isEmpty()) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Book not found"); + } + repository.deleteById(id); + } + } + """; + + @Autowired + private IRepository repository; + + @Autowired + private SynchronizationProcessor synchronizationProcessor; + + @Autowired + private RestAssuredExecutor restAssuredExecutor; + + @Test + void generated_dao_and_controller_serve_crud_over_http() { + writeAll(); + + // List on a fresh table returns 200 + a JSON array (may be empty or contain prior runs' data + // — assert only on the status code here). + restAssuredExecutor.execute(() -> given().when() + .get(CONTROLLER_BASE) + .then() + .statusCode(200), + ASSERTION_TIMEOUT_SECONDS); + + // POST persists a row through the @Inject-resolved repository. The retry-on-AssertionError + // executor doesn't return a value, so capture the IDENTITY-assigned id via AtomicReference. + AtomicReference created = new AtomicReference<>(); + restAssuredExecutor.execute(() -> created.set(given().when() + .contentType(ContentType.JSON) + .body("{\"title\":\"Dune\"}") + .post(CONTROLLER_BASE) + .then() + .statusCode(200) + .body(containsString("Dune")) + .extract() + .path("id")), + ASSERTION_TIMEOUT_SECONDS); + Integer createdId = created.get(); + + // GET /{id} resolves @PathParam binding. + restAssuredExecutor.execute(() -> given().when() + .get(CONTROLLER_BASE + "/" + createdId) + .then() + .statusCode(200) + .body(containsString("Dune")), + ASSERTION_TIMEOUT_SECONDS); + + // PUT updates an existing row. + restAssuredExecutor.execute(() -> given().when() + .contentType(ContentType.JSON) + .body("{\"title\":\"Dune Messiah\"}") + .put(CONTROLLER_BASE + "/" + createdId) + .then() + .statusCode(200) + .body(containsString("Dune Messiah")), + ASSERTION_TIMEOUT_SECONDS); + + // GET /count is non-negative and includes the row we just created. + restAssuredExecutor.execute(() -> given().when() + .get(CONTROLLER_BASE + "/count") + .then() + .statusCode(200) + .body(containsString("count")), + ASSERTION_TIMEOUT_SECONDS); + + // DELETE removes the row; subsequent GET returns 404. + restAssuredExecutor.execute(() -> given().when() + .delete(CONTROLLER_BASE + "/" + createdId) + .then() + .statusCode(200), + ASSERTION_TIMEOUT_SECONDS); + + restAssuredExecutor.execute(() -> given().when() + .get(CONTROLLER_BASE + "/" + createdId) + .then() + .statusCode(404), + ASSERTION_TIMEOUT_SECONDS); + + // The OpenAPI aggregator publishes one fragment per registered controller. + restAssuredExecutor.execute(() -> given().when() + .get("/services/openapi") + .then() + .statusCode(200) + .body(containsString(CONTROLLER_BASE)), + ASSERTION_TIMEOUT_SECONDS); + } + + private void writeAll() { + write(ENTITY_PATH, ENTITY_SOURCE); + write(REPOSITORY_PATH, REPOSITORY_SOURCE); + write(CONTROLLER_PATH, CONTROLLER_SOURCE); + synchronizationProcessor.forceProcessSynchronizers(); + } + + private void write(String path, String source) { + repository.createResource(path, source.getBytes(StandardCharsets.UTF_8), false, "text/x-java", true); + } + + @AfterEach + void cleanup() { + for (String path : List.of(ENTITY_PATH, REPOSITORY_PATH, CONTROLLER_PATH)) { + if (repository.hasResource(path)) { + repository.removeResource(path); + } + } + synchronizationProcessor.forceProcessSynchronizers(); + } +} From 23aadf8a236b5bb1d823bca0012f6e8d569dc3b3 Mon Sep 17 00:00:00 2001 From: ThuF Date: Fri, 22 May 2026 11:52:13 +0300 Subject: [PATCH 2/5] Add Angular Java templates --- components/group/group-templates/pom.xml | 8 + components/pom.xml | 12 + .../template-application-angular-java/pom.xml | 20 + .../project.json | 18 + .../template/template.extension | 5 + .../template/template.js | 33 + .../data/Repository.java.template | 32 + .../api/EntityController.java.template | 179 +++++- .../.gitignore | 2 + .../pom.xml | 24 + .../project.json | 5 + .../template/template.extension | 5 + .../template/template.js | 61 ++ .../template/ui/list.js | 116 ++++ .../template/ui/manage.js | 116 ++++ .../template/ui/masterDetailsList.js | 239 +++++++ .../template/ui/masterDetailsManage.js | 239 +++++++ .../template/ui/navigation.js | 18 + .../template/ui/perspective.js | 32 + .../template/ui/report.js | 120 ++++ .../template/ui/reportChart.js | 65 ++ .../template/ui/reportTable.js | 93 +++ .../template/ui/setting.js | 93 +++ .../template/ui/template.js | 34 + .../perspective-group.extension.template | 6 + .../navigation/perspective-group.js.template | 22 + .../ui/perspective/index.html.template | 50 ++ .../perspective/list/controller.js.template | 251 ++++++++ .../list/dialog-filter/controller.js.template | 217 +++++++ .../list/dialog-filter/index.html.template | 336 ++++++++++ .../dialog-filter/view.extension.template | 6 + .../list/dialog-filter/view.js.template | 20 + .../list/dialog-window/controller.js.template | 30 + .../list/dialog-window/index.html.template | 224 +++++++ .../dialog-window/view.extension.template | 6 + .../list/dialog-window/view.js.template | 17 + .../ui/perspective/list/index.html.template | 117 ++++ .../perspective/list/view.extension.template | 6 + .../ui/perspective/list/view.js.template | 20 + .../perspective/manage/controller.js.template | 342 ++++++++++ .../dialog-filter/controller.js.template | 217 +++++++ .../manage/dialog-filter/index.html.template | 336 ++++++++++ .../dialog-filter/view.extension.template | 6 + .../manage/dialog-filter/view.js.template | 20 + .../dialog-window/controller.js.template | 289 +++++++++ .../manage/dialog-window/index.html.template | 576 +++++++++++++++++ .../dialog-window/view.extension.template | 6 + .../manage/dialog-window/view.js.template | 17 + .../ui/perspective/manage/index.html.template | 120 ++++ .../manage/view.extension.template | 10 + .../ui/perspective/manage/view.js.template | 25 + .../master-list/controller.js.template | 250 ++++++++ .../master-list/detail/controller.js.template | 263 ++++++++ .../dialog-filter/controller.js.template | 203 ++++++ .../detail/dialog-filter/index.html.template | 336 ++++++++++ .../dialog-filter/view.extension.template | 6 + .../detail/dialog-filter/view.js.template | 20 + .../dialog-window/controller.js.template | 36 ++ .../detail/dialog-window/index.html.template | 240 +++++++ .../dialog-window/view.extension.template | 6 + .../detail/dialog-window/view.js.template | 17 + .../master-list/detail/index.html.template | 120 ++++ .../detail/view.extension.template | 6 + .../master-list/detail/view.js.template | 20 + .../dialog-filter/controller.js.template | 204 ++++++ .../dialog-filter/index.html.template | 336 ++++++++++ .../dialog-filter/view.extension.template | 6 + .../dialog-filter/view.js.template | 20 + .../dialog-window/controller.js.template | 30 + .../dialog-window/index.html.template | 222 +++++++ .../dialog-window/view.extension.template | 6 + .../dialog-window/view.js.template | 27 + .../master-list/index.html.template | 84 +++ .../main-details/controller.js.template | 57 ++ .../main-details/index.html.template | 248 ++++++++ .../main-details/view.extension.template | 6 + .../master-list/main-details/view.js.template | 20 + .../master-list/view.extension.template | 6 + .../perspective/master-list/view.js.template | 20 + .../master-manage/controller.js.template | 336 ++++++++++ .../detail/controller.js.template | 361 +++++++++++ .../dialog-filter/controller.js.template | 203 ++++++ .../detail/dialog-filter/index.html.template | 336 ++++++++++ .../dialog-filter/view.extension.template | 6 + .../detail/dialog-filter/view.js.template | 20 + .../dialog-window/controller.js.template | 278 +++++++++ .../detail/dialog-window/index.html.template | 578 +++++++++++++++++ .../dialog-window/view.extension.template | 6 + .../detail/dialog-window/view.js.template | 17 + .../master-manage/detail/index.html.template | 122 ++++ .../detail/view.extension.template | 6 + .../master-manage/detail/view.js.template | 20 + .../dialog-filter/controller.js.template | 204 ++++++ .../dialog-filter/index.html.template | 336 ++++++++++ .../dialog-filter/view.extension.template | 6 + .../dialog-filter/view.js.template | 20 + .../dialog-window/controller.js.template | 289 +++++++++ .../dialog-window/index.html.template | 580 +++++++++++++++++ .../dialog-window/view.extension.template | 6 + .../dialog-window/view.js.template | 27 + .../master-manage/index.html.template | 88 +++ .../main-details/controller.js.template | 363 +++++++++++ .../main-details/index.html.template | 589 ++++++++++++++++++ .../main-details/view.extension.template | 6 + .../main-details/view.js.template | 20 + .../master-manage/view.extension.template | 6 + .../master-manage/view.js.template | 20 + .../perspective.extension.template | 6 + .../ui/perspective/perspective.js.template | 29 + .../report-chart/controller.js.template | 218 +++++++ .../controller.js.template | 51 ++ .../dialog-window-filter/index.html.template | 462 ++++++++++++++ .../view.extension.template | 6 + .../dialog-window-filter/view.js.template | 17 + .../report-chart/index.html.template | 25 + .../report-chart/view.extension.template | 6 + .../perspective/report-chart/view.js.template | 20 + .../report-file/controller.js.template | 137 ++++ .../dialog-filter/controller.js.template | 56 ++ .../dialog-filter/index.html.template | 128 ++++ .../dialog-filter/view.extension.template | 6 + .../dialog-filter/view.js.template | 20 + .../dialog-print/controller.js.template | 66 ++ .../dialog-print/index.html.template | 62 ++ .../dialog-print/print.extension.template | 6 + .../dialog-print/print.js.template | 15 + .../dialog-window/controller.js.template | 18 + .../dialog-window/index.html.template | 107 ++++ .../dialog-window/view.extension.template | 6 + .../dialog-window/view.js.template | 20 + .../report-file/index.html.template | 68 ++ .../report-file/view.extension.template | 6 + .../perspective/report-file/view.js.template | 23 + .../report-table/controller.js.template | 224 +++++++ .../controller.js.template | 62 ++ .../dialog-window-filter/index.html.template | 463 ++++++++++++++ .../view.extension.template | 6 + .../dialog-window-filter/view.js.template | 17 + .../dialog-window/controller.js.template | 28 + .../dialog-window/index.html.template | 241 +++++++ .../dialog-window/view.extension.template | 6 + .../dialog-window/view.js.template | 17 + .../report-table/index.html.template | 114 ++++ .../report-table/view.extension.template | 6 + .../perspective/report-table/view.js.template | 20 + .../perspective/report/controller.js.template | 217 +++++++ .../dialog-filter/controller.js.template | 92 +++ .../report/dialog-filter/index.html.template | 324 ++++++++++ .../dialog-filter/view.extension.template | 6 + .../report/dialog-filter/view.js.template | 20 + .../dialog-print/controller.js.template | 130 ++++ .../report/dialog-print/index.html.template | 92 +++ .../dialog-print/print.extension.template | 6 + .../report/dialog-print/print.js.template | 15 + .../dialog-window/controller.js.template | 28 + .../report/dialog-window/index.html.template | 222 +++++++ .../dialog-window/view.extension.template | 6 + .../report/dialog-window/view.js.template | 20 + .../ui/perspective/report/index.html.template | 117 ++++ .../report/view.extension.template | 6 + .../ui/perspective/report/view.js.template | 23 + .../ui/translations-report.json.template | 30 + .../ui/translations.json.template | 68 ++ .../integration/tests/api/JavaTemplateIT.java | 64 ++ 164 files changed, 16791 insertions(+), 8 deletions(-) create mode 100644 components/template/template-application-angular-java/pom.xml create mode 100644 components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/project.json create mode 100644 components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.extension create mode 100644 components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.js create mode 100644 components/template/template-application-ui-angular-java/.gitignore create mode 100644 components/template/template-application-ui-angular-java/pom.xml create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/project.json create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.extension create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/list.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/manage.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/masterDetailsList.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/masterDetailsManage.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/navigation.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/perspective.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/report.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/reportChart.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/reportTable.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/setting.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/template.js create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/navigation/perspective-group.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/navigation/perspective-group.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/perspective.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/perspective.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/print.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/print.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/print.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/print.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/controller.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/index.html.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/view.extension.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/view.js.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/translations-report.json.template create mode 100644 components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/translations.json.template diff --git a/components/group/group-templates/pom.xml b/components/group/group-templates/pom.xml index 1695d6bfbf6..161c8560469 100644 --- a/components/group/group-templates/pom.xml +++ b/components/group/group-templates/pom.xml @@ -19,6 +19,10 @@ org.eclipse.dirigible dirigible-components-template-application-angular + + org.eclipse.dirigible + dirigible-components-template-application-angular-java + org.eclipse.dirigible dirigible-components-template-application-angular-v2 @@ -75,6 +79,10 @@ org.eclipse.dirigible dirigible-components-template-application-ui-angular + + org.eclipse.dirigible + dirigible-components-template-application-ui-angular-java + org.eclipse.dirigible dirigible-components-template-application-ui-angular-v2 diff --git a/components/pom.xml b/components/pom.xml index bab1070f9af..a9b02156b1c 100644 --- a/components/pom.xml +++ b/components/pom.xml @@ -237,6 +237,7 @@ template/template-application-angular + template/template-application-angular-java template/template-application-angular-v2 template/template-application-dao template/template-application-dao-java @@ -251,6 +252,7 @@ template/template-application-rest-v2 template/template-application-schema template/template-application-ui-angular + template/template-application-ui-angular-java template/template-application-ui-angular-v2 template/template-bpm template/template-camel @@ -1362,6 +1364,11 @@ dirigible-components-template-application-angular ${project.version} + + org.eclipse.dirigible + dirigible-components-template-application-angular-java + ${project.version} + org.eclipse.dirigible dirigible-components-template-application-angular-v2 @@ -1432,6 +1439,11 @@ dirigible-components-template-application-ui-angular ${project.version} + + org.eclipse.dirigible + dirigible-components-template-application-ui-angular-java + ${project.version} + org.eclipse.dirigible dirigible-components-template-application-ui-angular-v2 diff --git a/components/template/template-application-angular-java/pom.xml b/components/template/template-application-angular-java/pom.xml new file mode 100644 index 00000000000..dcf1c2ece15 --- /dev/null +++ b/components/template/template-application-angular-java/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + + org.eclipse.dirigible + dirigible-components-parent + 13.0.0-SNAPSHOT + ../../pom.xml + + + Components - Template - Application (Angular) - Java + dirigible-components-template-application-angular-java + jar + + + ../generation-header.txt + + + diff --git a/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/project.json b/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/project.json new file mode 100644 index 00000000000..91ccb1d11ac --- /dev/null +++ b/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/project.json @@ -0,0 +1,18 @@ +{ + "guid": "template-application-angular-java", + "dependencies": [ + { + "guid": "template-application-schema" + }, + { + "guid": "template-application-dao-java" + }, + { + "guid": "template-application-rest-java" + }, + { + "guid": "template-application-ui-angular-java" + } + ], + "actions": [] +} diff --git a/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.extension b/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.extension new file mode 100644 index 00000000000..ead843d6815 --- /dev/null +++ b/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.extension @@ -0,0 +1,5 @@ +{ + "extensionPoint": "platform-templates", + "module": "template-application-angular-java/template/template.js", + "description": "Application Template (with Angular UI) - Java" +} diff --git a/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.js b/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.js new file mode 100644 index 00000000000..70b05e32380 --- /dev/null +++ b/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.js @@ -0,0 +1,33 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +import * as schemaTemplateManager from "template-application-schema/template/template"; +import * as uiAngularjsTemplateManager from "template-application-ui-angular-java/template/template"; +import * as generateUtils from "service-generate/template/generateUtils"; +import * as parameterUtils from "service-generate/template/parameterUtils"; + +export function generate(model, parameters) { + model = JSON.parse(model).model; + let templateSources = getTemplate(parameters).sources; + parameterUtils.process(model, parameters); + return generateUtils.generateFiles(model, parameters, templateSources); +}; + +export function getTemplate(parameters) { + let schemaTemplate = schemaTemplateManager.getTemplate(parameters); + let uiAngularjsTemplate = uiAngularjsTemplateManager.getTemplate(parameters); + + let templateSources = []; + templateSources = templateSources.concat(schemaTemplate.sources); + templateSources = templateSources.concat(uiAngularjsTemplate.sources); + + return { + name: "Application - Full Stack - Java", + description: "Full stack application with a Database Schema, Java REST Services and an AngularJS UI", + extension: "model", + sources: templateSources, + parameters: parameterUtils.getUniqueParameters(schemaTemplate.parameters, uiAngularjsTemplate.parameters) + }; +}; diff --git a/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Repository.java.template b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Repository.java.template index e07c66dbbbf..3804ed07aea 100644 --- a/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Repository.java.template +++ b/components/template/template-application-dao-java/src/main/resources/META-INF/dirigible/template-application-dao-java/data/Repository.java.template @@ -3,10 +3,42 @@ package gen.${javaGenFolderName}.data.${javaPerspectiveName}; import org.eclipse.dirigible.components.data.store.java.repository.JavaRepository; import org.eclipse.dirigible.engine.java.annotations.Repository; +#foreach ($property in $properties) + #if($property.isCalculatedProperty && $property.calculatedPropertyExpressionCreate) + #set($haveCalculatedPropertyOnCreate = "true") + #end + #if($property.isCalculatedProperty && $property.calculatedPropertyExpressionUpdate) + #set($haveCalculatedPropertyOnUpdate = "true") + #end +#end @Repository public class ${name}Repository extends JavaRepository<${name}Entity> { public ${name}Repository() { super(${name}Entity.class); } +#if($haveCalculatedPropertyOnCreate) + + @Override + public ${name}Entity save(${name}Entity entity) { +#foreach ($property in $properties) +#if($property.isCalculatedProperty && $property.calculatedPropertyExpressionCreate) + entity.${property.name} = ${property.calculatedPropertyExpressionCreate}; +#end +#end + return super.save(entity); + } +#end +#if($haveCalculatedPropertyOnUpdate) + + @Override + public ${name}Entity update(${name}Entity entity) { +#foreach ($property in $properties) +#if($property.isCalculatedProperty && $property.calculatedPropertyExpressionUpdate) + entity.${property.name} = ${property.calculatedPropertyExpressionUpdate}; +#end +#end + return super.update(entity); + } +#end } diff --git a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template index a9a213ad73e..29a0de56cb7 100644 --- a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template +++ b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template @@ -1,11 +1,21 @@ package gen.${javaGenFolderName}.api.${javaPerspectiveName}; +#foreach ($property in $properties) +#if($property.roleRead || $property.roleWrite) +#set($isEntityPropertySecurityEnabled = "true") +#end +#end +#set($needsRoles = false) +#if($perspectiveRole || $roleRead || $roleWrite || $isEntityPropertySecurityEnabled) +#set($needsRoles = true) +#end import gen.${javaGenFolderName}.data.${javaPerspectiveName}.${name}Entity; import gen.${javaGenFolderName}.data.${javaPerspectiveName}.${name}Repository; import org.eclipse.dirigible.engine.java.annotations.Documentation; import org.eclipse.dirigible.engine.java.annotations.Inject; import org.eclipse.dirigible.engine.java.annotations.http.Body; +import org.eclipse.dirigible.engine.java.annotations.http.Context; import org.eclipse.dirigible.engine.java.annotations.http.Controller; import org.eclipse.dirigible.engine.java.annotations.http.Delete; import org.eclipse.dirigible.engine.java.annotations.http.Get; @@ -16,62 +26,215 @@ import org.eclipse.dirigible.engine.java.annotations.http.QueryParam; import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; +import jakarta.servlet.http.HttpServletRequest; + +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; @Controller @Documentation("${projectName} - ${name} Controller") public class ${name}Controller { + private static final Set FILTER_FIELDS = Set.of(#foreach($property in $properties)"${property.name}"#if($foreach.hasNext), #end#end); + @Inject private ${name}Repository repository; @Get @Documentation("List ${name}") public List<${name}Entity> getAll(@QueryParam("$limit") Integer limit, - @QueryParam("$offset") Integer offset) { + @QueryParam("$offset") Integer offset#if($needsRoles), + @Context HttpServletRequest request#end#if($layoutType == "MANAGE_DETAILS" || $layoutType == "LIST_DETAILS"), + @QueryParam("${masterEntityId}") String ${masterEntityId}#end) { +#if($needsRoles) + checkPermissions("read", request); +#end int actualLimit = limit != null ? limit.intValue() : 20; int actualOffset = offset != null ? offset.intValue() : 0; - return repository.findAll(actualLimit, actualOffset); +#if($layoutType == "MANAGE_DETAILS" || $layoutType == "LIST_DETAILS") + List<${name}Entity> result; + if (${masterEntityId} != null) { + Map params = new LinkedHashMap<>(); + params.put("${masterEntityId}", ${masterEntityId}); + result = repository.query("from ${name}Entity e where e.${masterEntityId} = :${masterEntityId}", params); + } else { + result = repository.findAll(actualLimit, actualOffset); + } +#else + List<${name}Entity> result = repository.findAll(actualLimit, actualOffset); +#end +#if($isEntityPropertySecurityEnabled) + result.forEach(e -> redactRead(e, request)); +#end + return result; } @Get("/count") @Documentation("Count ${name}") - public Map count() { + public Map count(#if($needsRoles)@Context HttpServletRequest request#end) { +#if($needsRoles) + checkPermissions("read", request); +#end return Map.of("count", repository.count()); } + @Post("/count") + @Documentation("Count ${name} with filter") + public Map countWithFilter(@Body Map filter#if($needsRoles), @Context HttpServletRequest request#end) { +#if($needsRoles) + checkPermissions("read", request); +#end + return Map.of("count", (long) runFilter(filter).size()); + } + + @Post("/search") + @Documentation("Search ${name}") + public List<${name}Entity> search(@Body Map filter#if($needsRoles), @Context HttpServletRequest request#end) { +#if($needsRoles) + checkPermissions("read", request); +#end + List<${name}Entity> result = runFilter(filter); +#if($isEntityPropertySecurityEnabled) + result.forEach(e -> redactRead(e, request)); +#end + return result; + } + @Get("/{id}") @Documentation("Get ${name} by id") - public ${name}Entity getById(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id) { - return repository.findOne(id) + public ${name}Entity getById(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id#if($needsRoles), @Context HttpServletRequest request#end) { +#if($needsRoles) + checkPermissions("read", request); +#end + ${name}Entity entity = repository.findOne(id) .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "${name} not found")); +#if($isEntityPropertySecurityEnabled) + redactRead(entity, request); +#end + return entity; } @Post @Documentation("Create ${name}") - public ${name}Entity create(@Body ${name}Entity entity) { + public ${name}Entity create(@Body ${name}Entity entity#if($needsRoles), @Context HttpServletRequest request#end) { +#if($needsRoles) + checkPermissions("write", request); +#end +#if($isEntityPropertySecurityEnabled) + applyOnCreate(entity, request); +#end validate(entity); return repository.save(entity); } @Put("/{id}") @Documentation("Update ${name} by id") - public ${name}Entity update(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id, @Body ${name}Entity entity) { + public ${name}Entity update(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id, @Body ${name}Entity entity#if($needsRoles), @Context HttpServletRequest request#end) { +#if($needsRoles) + checkPermissions("write", request); +#end +#if($isEntityPropertySecurityEnabled) + ${name}Entity existing = repository.findOne(id) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "${name} not found")); + mergeWritable(existing, entity, request); + validate(existing); + return repository.update(existing); +#else entity.#foreach($property in $properties)#if($property.dataPrimaryKey)${property.name}#end#end = id; validate(entity); return repository.update(entity); +#end } @Delete("/{id}") @Documentation("Delete ${name} by id") - public void deleteById(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id) { + public void deleteById(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id#if($needsRoles), @Context HttpServletRequest request#end) { +#if($needsRoles) + checkPermissions("write", request); +#end if (repository.findOne(id).isEmpty()) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "${name} not found"); } repository.deleteById(id); } + private List<${name}Entity> runFilter(Map filter) { + StringBuilder hql = new StringBuilder("from ${name}Entity e"); + Map params = new LinkedHashMap<>(); + if (filter != null && filter.get("equals") instanceof Map equals) { + boolean first = true; + for (Map.Entry entry : equals.entrySet()) { + String field = String.valueOf(entry.getKey()); + if (!FILTER_FIELDS.contains(field)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown filter field: " + field); + } + String paramName = "p" + params.size(); + hql.append(first ? " where e." : " and e.").append(field).append(" = :").append(paramName); + params.put(paramName, entry.getValue()); + first = false; + } + } + return repository.query(hql.toString(), params); + } +#if($needsRoles) + + private void checkPermissions(String op, HttpServletRequest request) { +#if($perspectiveRole) + if (!request.isUserInRole("${perspectiveRole}")) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } +#end +#if($roleRead) + if ("read".equals(op) && !(request.isUserInRole("${roleRead}")#if($roleWrite) || request.isUserInRole("${roleWrite}")#end)) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } +#end +#if($roleWrite) + if ("write".equals(op) && !request.isUserInRole("${roleWrite}")) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } +#end + } +#end +#if($isEntityPropertySecurityEnabled) + + private void redactRead(${name}Entity entity, HttpServletRequest request) { +#foreach ($property in $properties) +#if($property.roleRead) + if (!request.isUserInRole("${property.roleRead}")) { + entity.${property.name} = null; + } +#end +#end + } + + private void mergeWritable(${name}Entity target, ${name}Entity input, HttpServletRequest request) { +#foreach ($property in $properties) +#if(!$property.dataPrimaryKey) +#if($property.roleWrite) + if (request.isUserInRole("${property.roleWrite}")) { + target.${property.name} = input.${property.name}; + } +#else + target.${property.name} = input.${property.name}; +#end +#end +#end + } + + private void applyOnCreate(${name}Entity entity, HttpServletRequest request) { +#foreach ($property in $properties) +#if($property.roleWrite) + if (!request.isUserInRole("${property.roleWrite}")) { + entity.${property.name} = null; + } +#end +#end + } +#end + private static void validate(${name}Entity entity) { #foreach($property in $properties) #if($property.isRequiredProperty) diff --git a/components/template/template-application-ui-angular-java/.gitignore b/components/template/template-application-ui-angular-java/.gitignore new file mode 100644 index 00000000000..1dd33310812 --- /dev/null +++ b/components/template/template-application-ui-angular-java/.gitignore @@ -0,0 +1,2 @@ +/target/ +/target/ diff --git a/components/template/template-application-ui-angular-java/pom.xml b/components/template/template-application-ui-angular-java/pom.xml new file mode 100644 index 00000000000..16654f40855 --- /dev/null +++ b/components/template/template-application-ui-angular-java/pom.xml @@ -0,0 +1,24 @@ + + 4.0.0 + + + org.eclipse.dirigible + dirigible-components-parent + 13.0.0-SNAPSHOT + ../../pom.xml + + + Components - Template - Application - UI - AngularJS - Java + dirigible-components-template-application-ui-angular-java + jar + + + generate-sources + template-application-ui-angular-java + template-application-ui-angular-java + + ../generation-header.txt + + + \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/project.json b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/project.json new file mode 100644 index 00000000000..f72c4fa44cf --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/project.json @@ -0,0 +1,5 @@ +{ + "guid": "template-application-ui-angular-java", + "dependencies": [], + "actions": [] +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.extension b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.extension new file mode 100644 index 00000000000..ba9878a3a04 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.extension @@ -0,0 +1,5 @@ +{ + "module": "template-application-ui-angular-java/template/template.js", + "extensionPoint": "platform-templates", + "description": "Application Template - UI (Angular) - Java" +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.js new file mode 100644 index 00000000000..b5f49688dcc --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.js @@ -0,0 +1,61 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +import * as restTemplateManager from "template-application-rest-java/template/template"; +import * as uiTemplate from "template-application-ui-angular-java/template/ui/template"; +import * as generateUtils from "service-generate/template/generateUtils"; +import * as parameterUtils from "service-generate/template/parameterUtils"; + +export function generate(model, parameters) { + model = JSON.parse(model).model; + let templateSources = getTemplate(parameters).sources; + parameterUtils.process(model, parameters) + return generateUtils.generateFiles(model, parameters, templateSources); +}; + +export function getTemplate(parameters) { + let restTemplate = restTemplateManager.getTemplate(parameters); + + let templateSources = [ + ...restTemplate.sources, + ...uiTemplate.getSources(parameters) + ]; + + let templateParameters = getTemplateParameters(); + templateParameters = templateParameters.concat(restTemplate.parameters); + + return { + name: "Application - UI (AngularJS) - Java", + description: "Application With UI, Java REST APIs and DAOs", + extension: "model", + sources: templateSources, + parameters: templateParameters + }; +}; + +function getTemplateParameters() { + return [ + { + name: "brand", + label: "Brand", + placeholder: "Enter Brand" + }, + { + name: "brandUrl", + label: "Brand URL", + placeholder: "Enter Brand URL" + }, + { + name: "title", + label: "Title", + placeholder: "Enter Title" + }, + { + name: "description", + label: "Description", + placeholder: "Enter Description" + } + ]; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/list.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/list.js new file mode 100644 index 00000000000..2298b812a24 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/list.js @@ -0,0 +1,116 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +export function getSources(parameters) { + return [ + // Location: "gen/{{genFolderName}}/ui/perspective" + { + location: "/template-application-ui-angular-java/ui/perspective/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/index.html", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/perspective.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/perspective.extension", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/perspective.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/perspective.js", + collection: "uiListModels" + }, + // Location: "gen/{{genFolderName}}/ui/perspective/list" + { + location: "/template-application-ui-angular-java/ui/perspective/list/dialog-window/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/controller.js", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/list/dialog-window/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/index.html", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/list/dialog-window/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/view.extension", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/list/dialog-window/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/view.js", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/list/dialog-filter/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/controller.js", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/list/dialog-filter/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/index.html", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/list/dialog-filter/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/view.extension", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/list/dialog-filter/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/view.js", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/list/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/controller.js", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/list/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/index.html", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/list/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/view.extension", + collection: "uiListModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/list/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/view.js", + collection: "uiListModels" + } + ]; +}; diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/manage.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/manage.js new file mode 100644 index 00000000000..46266967886 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/manage.js @@ -0,0 +1,116 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +export function getSources(parameters) { + return [ + // Location: "gen/{{genFolderName}}/ui/perspective" + { + location: "/template-application-ui-angular-java/ui/perspective/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/index.html", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/perspective.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/perspective.extension", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/perspective.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/perspective.js", + collection: "uiManageModels" + }, + // Location: "gen/{{genFolderName}}/ui/perspective/manage" + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-window/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/controller.js", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-window/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/index.html", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/view.extension", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/view.js", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/controller.js", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/index.html", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/view.extension", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/view.js", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/controller.js", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/index.html", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/view.extension", + collection: "uiManageModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/view.js", + collection: "uiManageModels" + } + ]; +}; \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/masterDetailsList.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/masterDetailsList.js new file mode 100644 index 00000000000..2233200496a --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/masterDetailsList.js @@ -0,0 +1,239 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +export function getSources(parameters) { + return [ + ...getMaster(parameters), + ...getDetails(parameters) + ]; +}; + +function getMaster(parameters) { + return [ + // Location: "gen/{{genFolderName}}/ui/perspective" + { + location: "/template-application-ui-angular-java/ui/perspective/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/index.html", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/perspective.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/perspective.extension", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/perspective.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/perspective.js", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/controller.js", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/index.html", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/view.extension", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/view.js", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/main-details/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/main-details/controller.js", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/main-details/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/main-details/index.html", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/main-details/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/main-details/view.extension", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/main-details/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/main-details/view.js", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/controller.js", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/index.html", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/view.extension", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/view.js", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/controller.js", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/index.html", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/view.extension", + collection: "uiListMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/view.js", + collection: "uiListMasterModels" + }, + ]; +} + +function getDetails(parameters) { + return [ + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/controller.js", + collection: "uiListDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/index.html", + collection: "uiListDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/view.extension", + collection: "uiListDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/view.js", + collection: "uiListDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-window/controller.js", + collection: "uiListDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-window/index.html", + collection: "uiListDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-window/view.extension", + collection: "uiListDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-window/view.js", + collection: "uiListDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-filter/controller.js", + collection: "uiListDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-filter/index.html", + collection: "uiListDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-filter/view.extension", + collection: "uiListDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-filter/view.js", + collection: "uiListDetailsModels" + } + ]; +} diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/masterDetailsManage.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/masterDetailsManage.js new file mode 100644 index 00000000000..b4151de6d06 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/masterDetailsManage.js @@ -0,0 +1,239 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +export function getSources(parameters) { + return [ + ...getMaster(parameters), + ...getDetails(parameters) + ]; +}; + +function getMaster(parameters) { + return [ + // Location: "gen/{{genFolderName}}/ui/perspective" + { + location: "/template-application-ui-angular-java/ui/perspective/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/index.html", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/perspective.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/perspective.extension", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/perspective.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/perspective.js", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/controller.js", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/index.html", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/view.extension", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/view.js", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/main-details/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/main-details/controller.js", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/main-details/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/main-details/index.html", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/main-details/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/main-details/view.extension", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/main-details/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/main-details/view.js", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/controller.js", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/index.html", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/view.extension", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/view.js", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/controller.js", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/index.html", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/view.extension", + collection: "uiManageMasterModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/view.js", + collection: "uiManageMasterModels" + } + ]; +} + +function getDetails(parameters) { + return [ + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/controller.js", + collection: "uiManageDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/index.html", + collection: "uiManageDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/view.extension", + collection: "uiManageDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/view.js", + collection: "uiManageDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-window/controller.js", + collection: "uiManageDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-window/index.html", + collection: "uiManageDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-window/view.extension", + collection: "uiManageDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-window/view.js", + collection: "uiManageDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-filter/controller.js", + collection: "uiManageDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-filter/index.html", + collection: "uiManageDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-filter/view.extension", + collection: "uiManageDetailsModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{masterEntity}}/{{name}}/dialog-filter/view.js", + collection: "uiManageDetailsModels" + } + ]; +} diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/navigation.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/navigation.js new file mode 100644 index 00000000000..89e7b06dbce --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/navigation.js @@ -0,0 +1,18 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +export const getSources = () => ([{ + location: '/template-application-ui-angular-java/ui/navigation/perspective-group.extension.template', + action: 'generate', + rename: 'gen/{{genFolderName}}/navigation/{{navId}}/perspective-group.extension', + engine: 'velocity', + collection: 'uiNavigations' +}, { + location: '/template-application-ui-angular-java/ui/navigation/perspective-group.js.template', + action: 'generate', + rename: 'gen/{{genFolderName}}/navigation/{{navId}}/perspective-group.js', + engine: 'velocity', + collection: 'uiNavigations' +}]); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/perspective.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/perspective.js new file mode 100644 index 00000000000..b7dc6d35d77 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/perspective.js @@ -0,0 +1,32 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +export function getSources(parameters) { + return [{ + location: "/template-application-ui-angular-java/ui/perspective/index.html.template", + action: "generate", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/index.html", + engine: "velocity", + collection: "uiPerspectives" + }, { + location: "/template-application-ui-angular-java/ui/perspective/extensions/perspective/perspective.extension.template", + action: "generate", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/extensions/perspective/perspective.extension", + engine: "velocity", + collection: "uiPerspectives" + }, { + location: "/template-application-ui-angular-java/ui/perspective/extensions/perspective/perspective.js.template", + action: "generate", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/extensions/perspective/perspective.js", + engine: "velocity", + collection: "uiPerspectives" + }, { + location: "/template-application-ui-angular-java/ui/perspective/extensions/view.extensionpoint.template", + action: "generate", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/extensions/view.extensionpoint", + engine: "velocity", + collection: "uiPerspectives" + }]; +}; diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/report.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/report.js new file mode 100644 index 00000000000..805277f1568 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/report.js @@ -0,0 +1,120 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +export function getSources(parameters) { + return [ + // Location: "gen/{{genFolderName}}/ui/perspective/list" + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-window/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window/controller.js", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-window/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window/index.html", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-window/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window/view.extension", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-window/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window/view.js", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-filter/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-filter/controller.js", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-filter/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-filter/index.html", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-filter/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-filter/view.extension", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-filter/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-filter/view.js", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/controller.js", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/index.html", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/view.extension", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/view.js", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-print/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-print/controller.js", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-print/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-print/index.html", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-print/print.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-print/print.extension", + collection: "generateReportModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report/dialog-print/print.js.template", + action: "generate", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-print/print.js", + collection: "generateReportModels" + }]; +}; diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/reportChart.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/reportChart.js new file mode 100644 index 00000000000..bfb6c65f5b1 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/reportChart.js @@ -0,0 +1,65 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +export function getSources(parameters) { + return [ + // Location: "gen/{{genFolderName}}/ui/perspective/" + { + location: "/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window-filter/controller.js", + collection: "uiReportChartModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window-filter/index.html", + collection: "uiReportChartModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window-filter/view.extension", + collection: "uiReportChartModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window-filter/view.js", + collection: "uiReportChartModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-chart/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/controller.js", + collection: "uiReportChartModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-chart/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/index.html", + collection: "uiReportChartModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-chart/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/view.extension", + collection: "uiReportChartModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-chart/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/view.js", + collection: "uiReportChartModels" + }]; +}; \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/reportTable.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/reportTable.js new file mode 100644 index 00000000000..bb1bc336b97 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/reportTable.js @@ -0,0 +1,93 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +export function getSources(parameters) { + return [ + // Location: "gen/{{genFolderName}}/ui/perspective/" + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window/controller.js", + collection: "uiReportTableModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window/index.html", + collection: "uiReportTableModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window/view.extension", + collection: "uiReportTableModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window/view.js", + collection: "uiReportTableModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window-filter/controller.js", + collection: "uiReportTableModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window-filter/index.html", + collection: "uiReportTableModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window-filter/view.extension", + collection: "uiReportTableModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-window-filter/view.js", + collection: "uiReportTableModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/controller.js", + collection: "uiReportTableModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/index.html", + collection: "uiReportTableModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/view.extension", + collection: "uiReportTableModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/report-table/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/Reports/{{name}}/view.js", + collection: "uiReportTableModels" + }]; +}; \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/setting.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/setting.js new file mode 100644 index 00000000000..e1d07e8a39e --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/setting.js @@ -0,0 +1,93 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +export function getSources(parameters) { + return [ + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-window/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/controller.js", + collection: "uiSettingModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-window/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/index.html", + collection: "uiSettingModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/view.extension", + collection: "uiSettingModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-window/view.js", + collection: "uiSettingModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/controller.js", + collection: "uiSettingModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/index.html", + collection: "uiSettingModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/view.extension", + collection: "uiSettingModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/dialog-filter/view.js", + collection: "uiSettingModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/controller.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/controller.js", + collection: "uiSettingModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/index.html.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/index.html", + collection: "uiSettingModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/view.extension.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/view.extension", + collection: "uiSettingModels" + }, + { + location: "/template-application-ui-angular-java/ui/perspective/manage/view.js.template", + action: "generate", + engine: "velocity", + rename: "gen/{{genFolderName}}/ui/{{perspectiveName}}/{{name}}/view.js", + collection: "uiSettingModels" + } + ]; +}; \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/template.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/template.js new file mode 100644 index 00000000000..4a8b5f483a5 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/ui/template.js @@ -0,0 +1,34 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +import * as listTemplate from "template-application-ui-angular-java/template/ui/list"; +import * as manageTemplate from "template-application-ui-angular-java/template/ui/manage"; +import * as masterDetailsListTemplate from "template-application-ui-angular-java/template/ui/masterDetailsList"; +import * as masterDetailsManageTemplate from "template-application-ui-angular-java/template/ui/masterDetailsManage"; +import * as settingTemplate from "template-application-ui-angular-java/template/ui/setting"; +import * as reportTemplate from "template-application-ui-angular-java/template/ui/report"; +import * as reportChartTemplate from "template-application-ui-angular-java/template/ui/reportChart"; +import * as reportTableTemplate from "template-application-ui-angular-java/template/ui/reportTable"; +import * as navigation from "template-application-ui-angular-java/template/ui/navigation"; +// import * as perspective from "template-application-ui-angular-java/template/ui/perspective"; + +export function getSources(parameters) { + return [ + { + location: "/template-application-ui-angular-java/ui/translations.json.template", + action: "translate", + }, + ...listTemplate.getSources(parameters), + ...manageTemplate.getSources(parameters), + ...masterDetailsListTemplate.getSources(parameters), + ...masterDetailsManageTemplate.getSources(parameters), + ...settingTemplate.getSources(parameters), + ...reportTemplate.getSources(parameters), + ...reportChartTemplate.getSources(parameters), + ...reportTableTemplate.getSources(parameters), + ...navigation.getSources(parameters), + //...perspective.getSources(parameters), + ]; +}; \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/navigation/perspective-group.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/navigation/perspective-group.extension.template new file mode 100644 index 00000000000..0147f5c27e6 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/navigation/perspective-group.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/navigation/${navId}/perspective-group.js", + "extensionPoint": "application-perspectives", + "description": "${projectName} - Perspective Group - ${navLabel}"#if($navRole || $roleRead || $roleWrite), + "role": "#if($navRole)${navRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/navigation/perspective-group.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/navigation/perspective-group.js.template new file mode 100644 index 00000000000..18b13e33c2e --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/navigation/perspective-group.js.template @@ -0,0 +1,22 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +exports.getPerspectiveGroup = () => ({ + id: '${navId}', + label: '${navLabel}', + translation: { + key: '$projectName:${tprefix}.t.${navId}', + }, +#if($navHeader) + header: '${navHeader}', + headerTranslation: { + key: '$projectName:${tprefix}.t.${navId}nheader', + }, +#end + expanded: ${navExpanded}, + order: ${navOrder}, + icon: '${navIcon}', + items: [] +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/index.html.template new file mode 100644 index 00000000000..bdef8c38339 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/index.html.template @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + {{'$projectName:${tprefix}.state.busy' | t}} + + + {{'$projectName:${tprefix}.messages.error.loading' | t}} + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/controller.js.template new file mode 100644 index 00000000000..81901e268f4 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/controller.js.template @@ -0,0 +1,251 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService) => { + const Dialogs = new DialogHub(); + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 20; + + //-----------------Custom Actions-------------------// + Extensions.getWindows(['${projectName}-custom-action']).then((response) => { + $scope.pageActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && (e.type === 'page' || e.type === undefined)); + $scope.entityActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && e.type === 'entity'); + }); + + $scope.triggerPageAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + maxWidth: action.maxWidth, + maxHeight: action.maxHeight, + closeButton: true + }); + }; + + $scope.triggerEntityAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + params: { + id: $scope.entity.${primaryKeysString} + }, + closeButton: true + }); + }; + //-----------------Custom Actions-------------------// + + function resetPagination() { + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 20; + } + resetPagination(); + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', handler: (data) => { + resetPagination(); + $scope.filter = data.filter; + $scope.filterEntity = data.entity; + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + //-----------------Events-------------------// + + $scope.loadPage = (pageNumber, filter) => { + if (!filter && $scope.filter) { + filter = $scope.filter; + } + $scope.dataPage = pageNumber; + EntityService.count(filter).then((resp) => { + if (resp.data) { + $scope.dataCount = resp.data.count; + } + let offset = (pageNumber - 1) * $scope.dataLimit; + let limit = $scope.dataLimit; + let request; + if (filter) { + if (!filter.$filter) { + filter.$filter = {}; + } + filter.$filter.offset = offset; + filter.$filter.limit = limit; + request = EntityService.search(filter); + } else { + request = EntityService.list(offset, limit); + } + request.then((response) => { +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + if (options${property.name}HasMore) { + const options${property.name}SearchValues = Array.from(new Set(response.data.map(e => e.${property.name}))); + if (options${property.name}SearchValues.length > 0) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownKey}', operator: 'IN', value: options${property.name}SearchValues } + ] + }).then((response) => { + ${dollar}scope.options${property.name}.push(...response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + }))); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + } + } +#end +#end +#end +#if($hasDates) + response.data.forEach(e => { +#foreach ($property in $properties) +#if($property.isDateType) + if (e.${property.name}) { + e.${property.name} = new Date(e.${property.name}); + } +#end +#end + }); + +#end + $scope.data = response.data; + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCount', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + $scope.loadPage($scope.dataPage, $scope.filter); + + $scope.selectEntity = (entity) => { + $scope.selectedEntity = entity; + }; + + $scope.openDetails = (entity) => { + $scope.selectedEntity = entity; + Dialogs.showWindow({ + id: '${name}-details', + params: { + action: 'select', + entity: entity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + }); + }; + + $scope.openFilter = () => { + Dialogs.showWindow({ + id: '${name}-filter', + params: { + entity: $scope.filterEntity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + }); + }; +#if($hasDropdowns) + + //----------------Dropdowns-----------------// +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end +#foreach ($property in $properties) +#if ($property.widgetType == "DROPDOWN") + let options${property.name}HasMore = true; + + ${dollar}http.get('${property.widgetDropdownControllerUrl}/count').then((response) => { + const options${property.name}Count = response.data.count; + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + options${property.name}HasMore = options${property.name}Count > ${dollar}scope.options${property.name}.length; + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + +#end +#end +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = (optionKey) => { +#if($property.widgetDropDownMultiSelect) + const values = []; + if (Array.isArray(optionKey)) { + optionKey = optionKey.join(); + } + optionKey.split(',').map(e => parseInt(e)).forEach(key => { + const found = ${dollar}scope.options${property.name}.find(e => e.value === key); + if (found) { + values.push(found.text); + } + }); + return values.join(', '); +#else + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; +#end + }; +#end +#end + //----------------Dropdowns-----------------// +#end + + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/controller.js.template new file mode 100644 index 00000000000..b0b5605d13b --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/controller.js.template @@ -0,0 +1,217 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end ViewParameters, LocaleService) => { + const Dialogs = new DialogHub(); + let description = 'Description'; + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + + LocaleService.onInit(() => { + description = LocaleService.t('$projectName:${tprefix}.defaults.description'); + }); + + let params = ViewParameters.get(); + if (Object.keys(params).length) { +#foreach ($property in $properties) +#if($property.isDateType) + if (params?.entity?.${property.name}From) { + params.entity.${property.name}From = new Date(params.entity.${property.name}From); + } + if (params?.entity?.${property.name}To) { + params.entity.${property.name}To = new Date(params.entity.${property.name}To); + } +#end +#end + $scope.entity = params.entity ?? {}; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } + + $scope.filter = () => { + let entity = $scope.entity; + const filter = { + $filter: { + conditions: [], + sorts: [], + limit: 20, + offset: 0 + } + }; +#foreach ($property in $properties) +#if($property.dataTypeTypescript == 'number') + if (entity.${property.name} !== undefined) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'boolean') + if (entity.${property.name} !== undefined && entity.is${property.name}Indeterminate === false) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'string') + if (entity.${property.name}) { + const condition = { propertyName: '${property.name}', operator: 'LIKE', value: `%$dollar{entity.${property.name}}%` }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'Date') + if (entity.${property.name}From) { + const condition = { propertyName: '${property.name}', operator: 'GE', value: entity.${property.name}From }; + filter.$filter.conditions.push(condition); + } + if (entity.${property.name}To) { + const condition = { propertyName: '${property.name}', operator: 'LE', value: entity.${property.name}To }; + filter.$filter.conditions.push(condition); + } +#end +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', data: { + entity: entity, + filter: filter + }}); + $scope.cancel(); + }; + + $scope.resetFilter = () => { + $scope.entity = {}; + $scope.filter(); +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + lastSearchValues${property.name}.clear(); + allValues${property.name}.length = 0; +#end +#end +#end + }; + + $scope.alert = (message) => { + if (message) Dialogs.showAlert({ + title: description, + message: message, + type: AlertTypes.Information, + preformatted: true, + }); + }; + + $scope.cancel = () => { + Dialogs.closeWindow({ id: '${name}-filter' }); + }; + + $scope.clearErrorMessage = () => { + $scope.errorMessage = null; + }; + +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const lastSearchValues${property.name} = new Set(); + const allValues${property.name} = []; + let loadMoreOptions${property.name}Counter = 0; + $scope.options${property.name}Loading = false; + $scope.options${property.name}HasMore = true; + + $scope.loadMoreOptions${property.name} = () => { + const limit = 20; + $scope.options${property.name}Loading = true; + ${dollar}http.get(`${property.widgetDropdownControllerUrl}?$limit=${dollar}{limit}&$offset=${dollar}{++loadMoreOptions${property.name}Counter * limit}`) + .then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const resultValues = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + const newValues = []; + resultValues.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + newValues.push(e); + } + }); + newValues.forEach(e => { + if (!${dollar}scope.options${property.name}.find(o => o.value === e.value)) { + ${dollar}scope.options${property.name}.push(e); + } + }) + $scope.options${property.name}HasMore = resultValues.length > 0; + $scope.options${property.name}Loading = false; + }, (error) => { + $scope.options${property.name}Loading = false; + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }; + + $scope.onOptions${property.name}Change = (event) => { + if (allValues${property.name}.length === 0) { + allValues${property.name}.push(...${dollar}scope.options${property.name}); + } + if (event.originalEvent.target.value === '') { + allValues${property.name}.sort((a, b) => a.text.localeCompare(b.text)); + ${dollar}scope.options${property.name} = allValues${property.name}; + $scope.options${property.name}HasMore = true; + } else if (isText(event.which)) { + $scope.options${property.name}HasMore = false; + let cacheHit = false; + Array.from(lastSearchValues${property.name}).forEach(e => { + if (event.originalEvent.target.value.startsWith(e)) { + cacheHit = true; + } + }) + if (!cacheHit) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownValue}', operator: 'LIKE', value: `${dollar}{event.originalEvent.target.value}%` } + ] + }).then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const searchResult = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + searchResult.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + } + }); + ${dollar}scope.options${property.name} = allValues${property.name}.filter(e => e.text.toLowerCase().startsWith(event.originalEvent.target.value.toLowerCase())); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + lastSearchValues${property.name}.add(event.originalEvent.target.value); + } + } + }; + +#end +#end + function isText(keycode) { + if ((keycode >= 48 && keycode <= 90) || (keycode >= 96 && keycode <= 111) || (keycode >= 186 && keycode <= 222) || [8, 46, 173].includes(keycode)) return true; + return false; + } + +#end +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/index.html.template new file mode 100644 index 00000000000..c8776cc84a3 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/index.html.template @@ -0,0 +1,336 @@ +#set($dollar = '$') + + + + + + + + + + + + + + + + {{ errorMessage }} + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +

+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + + More Options + + +
+ +#elseif($property.widgetType == "CHECKBOX") + +
+
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#end +#end +#end + + + + + + + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/view.extension.template new file mode 100644 index 00000000000..8b596562b61 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-filter/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/view.js.template new file mode 100644 index 00000000000..3a25b9a3a55 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-filter/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-filter', + label: '${name} Filter', + translation: { + key: '$projectName:${tprefix}.extName', + options: { + content: '$t($projectName:${tprefix}.t.$dataName) $t($projectName:${tprefix}.defaults.filter)', + } + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-filter/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/controller.js.template new file mode 100644 index 00000000000..924391a6ad9 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/controller.js.template @@ -0,0 +1,30 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, ViewParameters) => { + $scope.entity = {}; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { + $scope.action = 'select'; + +#foreach ($property in $properties) +#if($property.isDateType) + if (params.entity.${property.name}) { + params.entity.${property.name} = new Date(params.entity.${property.name}); + } +#end +#end + $scope.entity = params.entity; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}?.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/index.html.template new file mode 100644 index 00000000000..dd2f95a212e --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/index.html.template @@ -0,0 +1,224 @@ +#set($dollar = '$') + + + + + + + + + + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#end +#end +#end +
+
+
+ + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/view.extension.template new file mode 100644 index 00000000000..e0467a1d892 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-window/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/view.js.template new file mode 100644 index 00000000000..9f6c7c33bdd --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/dialog-window/view.js.template @@ -0,0 +1,17 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-details', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-window/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/index.html.template new file mode 100644 index 00000000000..ca42f89ab0f --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/index.html.template @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + {{'$projectName:${tprefix}.defaults.items' | t}} + + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.widgetIsMajor) + +#end +#end + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.widgetIsMajor) +#if($property.widgetType == "DROPDOWN") + +#elseif($property.widgetType == "EMAIL") + +#elseif($property.widgetType == "URL") + +#elseif($property.widgetType == "TEL") + +#elseif($property.widgetType == "COLOR") + +#elseif($property.widgetType == "WEEK") + +#elseif($property.widgetType == "MONTH") + +#elseif($property.widgetType == "TIME") + +#elseif($property.widgetType == "DATETIME-LOCAL") + +#elseif($property.widgetType == "DATE") + +#elseif($property.widgetType == "CHECKBOX") + +#else + +#end +#end +#end + + + +
{{ '$projectName:${tprefix}.t.$property.dataName' | t:'$property.name' }}
{{'$projectName:${tprefix}.messages.noData' | t}}
+ {{options${property.name}Value(next.${property.name})}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + + + + + + + + + + + + + + + {{next.${property.name}}} + + + + + + + + + + + +
+
+ + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/view.extension.template new file mode 100644 index 00000000000..f9ae92d4291 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/view.js", + "extensionPoint": "application-views", + "description": "${projectName} - Application View"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/view.js.template new file mode 100644 index 00000000000..3e9644ca619 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/list/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + region: 'center', + lazyLoad: false, + autoFocusTab: true, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/controller.js.template new file mode 100644 index 00000000000..b8ecaa431d9 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/controller.js.template @@ -0,0 +1,342 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService, ButtonStates) => { + const Dialogs = new DialogHub(); + let translated = { + yes: 'Yes', + no: 'No', + deleteConfirm: 'Are you sure you want to delete ${name}? This action cannot be undone.', + deleteTitle: 'Delete ${name}?' + }; + + LocaleService.onInit(() => { + translated.yes = LocaleService.t('$projectName:${tprefix}.defaults.yes'); + translated.no = LocaleService.t('$projectName:${tprefix}.defaults.no'); + translated.deleteTitle = LocaleService.t('$projectName:${tprefix}.defaults.deleteTitle', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + translated.deleteConfirm = LocaleService.t('$projectName:${tprefix}.messages.deleteConfirm', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + }); + + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 20; + + //-----------------Custom Actions-------------------// + Extensions.getWindows(['${projectName}-custom-action']).then((response) => { + $scope.pageActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && (e.type === 'page' || e.type === undefined)); + $scope.entityActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && e.type === 'entity'); + }); + + $scope.triggerPageAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + maxWidth: action.maxWidth, + maxHeight: action.maxHeight, + closeButton: true + }); + }; + + $scope.triggerEntityAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + params: { + id: $scope.entity.${primaryKeysString} + }, + closeButton: true + }); + }; + //-----------------Custom Actions-------------------// + + function resetPagination() { + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 20; + } + resetPagination(); + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entityCreated', handler: () => { + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entityUpdated', handler: () => { + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', handler: (data) => { + resetPagination(); + $scope.filter = data.filter; + $scope.filterEntity = data.entity; + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + //-----------------Events-------------------// + + $scope.loadPage = (pageNumber, filter) => { + if (!filter && $scope.filter) { + filter = $scope.filter; + } + $scope.dataPage = pageNumber; + EntityService.count(filter).then((resp) => { + if (resp.data) { + $scope.dataCount = resp.data.count; + } + let offset = (pageNumber - 1) * $scope.dataLimit; + let limit = $scope.dataLimit; + let request; + if (filter) { + if (!filter.$filter) { + filter.$filter = {}; + } + filter.$filter.offset = offset; + filter.$filter.limit = limit; + request = EntityService.search(filter); + } else { + request = EntityService.list(offset, limit); + } + request.then((response) => { +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + if (options${property.name}HasMore) { + const options${property.name}SearchValues = Array.from(new Set(response.data.map(e => e.${property.name}))); + if (options${property.name}SearchValues.length > 0) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownKey}', operator: 'IN', value: options${property.name}SearchValues } + ] + }).then((response) => { + ${dollar}scope.options${property.name}.push(...response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + }))); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + } + } +#end +#end +#end +#if($hasDates) + response.data.forEach(e => { +#foreach ($property in $properties) +#if($property.isDateType) + if (e.${property.name}) { + e.${property.name} = new Date(e.${property.name}); + } +#end +#end + }); + +#end + $scope.data = response.data; + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCount', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + $scope.loadPage($scope.dataPage, $scope.filter); + + $scope.selectEntity = (entity) => { + $scope.selectedEntity = entity; + }; + + $scope.openDetails = (entity) => { + $scope.selectedEntity = entity; + Dialogs.showWindow({ + id: '${name}-details', + params: { + action: 'select', + entity: entity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + closeButton: true, + }); + }; + + $scope.openFilter = () => { + Dialogs.showWindow({ + id: '${name}-filter', + params: { + entity: $scope.filterEntity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + closeButton: true, + }); + }; + + $scope.createEntity = () => { + $scope.selectedEntity = null; + Dialogs.showWindow({ + id: '${name}-details', + params: { + action: 'create', + entity: {}, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + closeButton: false, + }); + }; + + $scope.updateEntity = (entity) => { + Dialogs.showWindow({ + id: '${name}-details', + params: { + action: 'update', + entity: entity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + closeButton: false, + }); + }; + + $scope.deleteEntity = (entity) => { + let id = entity.${primaryKeysString}; + Dialogs.showDialog({ + title: translated.deleteTitle, + message: translated.deleteConfirm, + buttons: [{ + id: 'delete-btn-yes', + state: ButtonStates.Emphasized, + label: translated.yes, + }, { + id: 'delete-btn-no', + label: translated.no, + }] + }).then((buttonId) => { + if (buttonId === 'delete-btn-yes') { + EntityService.delete(id).then((response) => { + $scope.loadPage($scope.dataPage, $scope.filter); + Dialogs.triggerEvent('${projectName}.${perspectiveName}.${name}.clearDetails'); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToDelete', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + } + }); + }; +#if($hasDropdowns) + + //----------------Dropdowns-----------------// +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end + +#foreach ($property in $properties) +#if ($property.widgetType == "DROPDOWN") + let options${property.name}HasMore = true; + + ${dollar}http.get('${property.widgetDropdownControllerUrl}/count').then((response) => { + const options${property.name}Count = response.data.count; + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + options${property.name}HasMore = options${property.name}Count > ${dollar}scope.options${property.name}.length; + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); +#end +#end + +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = (optionKey) => { +#if($property.widgetDropDownMultiSelect) + const values = []; + if (Array.isArray(optionKey)) { + optionKey = optionKey.join(); + } + optionKey.split(',').map(e => parseInt(e)).forEach(key => { + const found = ${dollar}scope.options${property.name}.find(e => e.value === key); + if (found) { + values.push(found.text); + } + }); + return values.join(', '); +#else + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; +#end + }; +#end +#end + //----------------Dropdowns-----------------// +#end + + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/controller.js.template new file mode 100644 index 00000000000..2fe3e8a30ae --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/controller.js.template @@ -0,0 +1,217 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end ViewParameters, LocaleService) => { + const Dialogs = new DialogHub(); + let description = 'Description'; + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + + LocaleService.onInit(() => { + description = LocaleService.t('$projectName:${tprefix}.defaults.description'); + }); + + let params = ViewParameters.get(); + if (Object.keys(params).length) { +#foreach ($property in $properties) +#if($property.isDateType) + if (params?.entity?.${property.name}From) { + params.entity.${property.name}From = new Date(params.entity.${property.name}From); + } + if (params?.entity?.${property.name}To) { + params.entity.${property.name}To = new Date(params.entity.${property.name}To); + } +#end +#end + $scope.entity = params.entity ?? {}; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } + + $scope.filter = () => { + let entity = $scope.entity; + const filter = { + $filter: { + conditions: [], + sorts: [], + limit: 20, + offset: 0 + } + }; +#foreach ($property in $properties) +#if($property.dataTypeTypescript == 'number') + if (entity.${property.name} !== undefined) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'boolean') + if (entity.${property.name} !== undefined && entity.is${property.name}Indeterminate === false) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'string') + if (entity.${property.name}) { + const condition = { propertyName: '${property.name}', operator: 'LIKE', value: `%$dollar{entity.${property.name}}%` }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'Date') + if (entity.${property.name}From) { + const condition = { propertyName: '${property.name}', operator: 'GE', value: entity.${property.name}From }; + filter.$filter.conditions.push(condition); + } + if (entity.${property.name}To) { + const condition = { propertyName: '${property.name}', operator: 'LE', value: entity.${property.name}To }; + filter.$filter.conditions.push(condition); + } +#end +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', data: { + entity: entity, + filter: filter + }}); + $scope.cancel(); + }; + + $scope.resetFilter = () => { + $scope.entity = {}; + $scope.filter(); +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + lastSearchValues${property.name}.clear() + allValues${property.name}.length = 0; +#end +#end +#end + }; + + $scope.alert = (message) => { + if (message) Dialogs.showAlert({ + title: description, + message: message, + type: AlertTypes.Information, + preformatted: true, + }); + }; + + $scope.cancel = () => { + Dialogs.closeWindow({ id: '${name}-filter' }); + }; + + $scope.clearErrorMessage = () => { + $scope.errorMessage = null; + }; + +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const lastSearchValues${property.name} = new Set(); + const allValues${property.name} = []; + let loadMoreOptions${property.name}Counter = 0; + $scope.options${property.name}Loading = false; + $scope.options${property.name}HasMore = true; + + $scope.loadMoreOptions${property.name} = () => { + const limit = 20; + $scope.options${property.name}Loading = true; + ${dollar}http.get(`${property.widgetDropdownControllerUrl}?$limit=${dollar}{limit}&$offset=${dollar}{++loadMoreOptions${property.name}Counter * limit}`) + .then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const resultValues = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + const newValues = []; + resultValues.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + newValues.push(e); + } + }); + newValues.forEach(e => { + if (!${dollar}scope.options${property.name}.find(o => o.value === e.value)) { + ${dollar}scope.options${property.name}.push(e); + } + }) + $scope.options${property.name}HasMore = resultValues.length > 0; + $scope.options${property.name}Loading = false; + }, (error) => { + $scope.options${property.name}Loading = false; + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }; + + $scope.onOptions${property.name}Change = (event) => { + if (allValues${property.name}.length === 0) { + allValues${property.name}.push(...${dollar}scope.options${property.name}); + } + if (event.originalEvent.target.value === '') { + allValues${property.name}.sort((a, b) => a.text.localeCompare(b.text)); + ${dollar}scope.options${property.name} = allValues${property.name}; + $scope.options${property.name}HasMore = true; + } else if (isText(event.which)) { + $scope.options${property.name}HasMore = false; + let cacheHit = false; + Array.from(lastSearchValues${property.name}).forEach(e => { + if (event.originalEvent.target.value.startsWith(e)) { + cacheHit = true; + } + }) + if (!cacheHit) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownValue}', operator: 'LIKE', value: `${dollar}{event.originalEvent.target.value}%` } + ] + }).then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const searchResult = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + searchResult.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + } + }); + ${dollar}scope.options${property.name} = allValues${property.name}.filter(e => e.text.toLowerCase().startsWith(event.originalEvent.target.value.toLowerCase())); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + lastSearchValues${property.name}.add(event.originalEvent.target.value); + } + } + }; + +#end +#end + function isText(keycode) { + if ((keycode >= 48 && keycode <= 90) || (keycode >= 96 && keycode <= 111) || (keycode >= 186 && keycode <= 222) || [8, 46, 173].includes(keycode)) return true; + return false; + } + +#end +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/index.html.template new file mode 100644 index 00000000000..80369b41315 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/index.html.template @@ -0,0 +1,336 @@ +#set($dollar = '$') + + + + + + + + + + + + + + + + {{ errorMessage }} + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + + More Options + + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.extension.template new file mode 100644 index 00000000000..8b596562b61 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-filter/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.js.template new file mode 100644 index 00000000000..3a25b9a3a55 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-filter/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-filter', + label: '${name} Filter', + translation: { + key: '$projectName:${tprefix}.extName', + options: { + content: '$t($projectName:${tprefix}.t.$dataName) $t($projectName:${tprefix}.defaults.filter)', + } + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-filter/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/controller.js.template new file mode 100644 index 00000000000..6b37bddddbd --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/controller.js.template @@ -0,0 +1,289 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', ($scope, ${dollar}http, ViewParameters, LocaleService, EntityService) => { + const Dialogs = new DialogHub(); + const Notifications = new NotificationHub(); + let description = 'Description'; + let propertySuccessfullyCreated = '${name} successfully created'; + let propertySuccessfullyUpdated = '${name} successfully updated'; + + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + $scope.formHeaders = { + select: '${name} Details', + create: 'Create ${name}', + update: 'Update ${name}' + }; + $scope.action = 'select'; + + LocaleService.onInit(() => { + description = LocaleService.t('$projectName:${tprefix}.defaults.description'); + $scope.formHeaders.select = LocaleService.t('$projectName:${tprefix}.defaults.formHeadSelect', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + $scope.formHeaders.create = LocaleService.t('$projectName:${tprefix}.defaults.formHeadCreate', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + $scope.formHeaders.update = LocaleService.t('$projectName:${tprefix}.defaults.formHeadUpdate', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + propertySuccessfullyCreated = LocaleService.t('$projectName:${tprefix}.messages.propertySuccessfullyCreated', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + propertySuccessfullyUpdated = LocaleService.t('$projectName:${tprefix}.messages.propertySuccessfullyUpdated', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + }); + + let params = ViewParameters.get(); + if (Object.keys(params).length) { + $scope.action = params.action; +#foreach ($property in $properties) +#if($property.isDateType) + if (params.entity.${property.name}) { + params.entity.${property.name} = new Date(params.entity.${property.name}); + } +#end +#end + $scope.entity = params.entity; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}?.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } + + $scope.create = () => { + let entity = $scope.entity; + entity[$scope.selectedMainEntityKey] = $scope.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN" && $property.widgetDropDownMultiSelect) + if (entity.${property.name}) { + entity.${property.name} = entity.${property.name}.join(); + } +#end +#end + EntityService.create(entity).then((response) => { + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entityCreated', data: response.data }); + Notifications.show({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + description: propertySuccessfullyCreated, + type: 'positive' + }); + $scope.cancel(); + }, (error) => { + const message = error.data ? error.data.message : ''; + $scope.$evalAsync(() => { + $scope.errorMessage = LocaleService.t('$projectName:${tprefix}.messages.error.unableToCreate', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }); + }); + console.error('EntityService:', error); + }); + }; + + $scope.update = () => { + let id = ${dollar}scope.entity.${primaryKeysString}; + let entity = $scope.entity; + entity[$scope.selectedMainEntityKey] = $scope.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN" && $property.widgetDropDownMultiSelect) + if (entity.${property.name}) { + entity.${property.name} = entity.${property.name}.join(); + } +#end +#end + EntityService.update(id, entity).then((response) => { + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entityUpdated', data: response.data }); + Notifications.show({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + description: propertySuccessfullyUpdated, + type: 'positive' + }); + $scope.cancel(); + }, (error) => { + const message = error.data ? error.data.message : ''; + $scope.$evalAsync(() => { + $scope.errorMessage = LocaleService.t('$projectName:${tprefix}.messages.error.unableToUpdate', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }); + }); + console.error('EntityService:', error); + }); + }; + +#if($hasDropdowns) +#foreach ($property in $properties) +#if ($property.widgetType == "DROPDOWN") + ${dollar}scope.service${property.name} = '${property.widgetDropdownControllerUrl}'; + + $scope.options${property.name} = []; + + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + + const lastSearchValues${property.name} = new Set(); + const allValues${property.name} = []; + let loadMoreOptions${property.name}Counter = 0; + $scope.options${property.name}Loading = false; + $scope.options${property.name}HasMore = true; + + $scope.loadMoreOptions${property.name} = () => { + const limit = 20; + $scope.options${property.name}Loading = true; + ${dollar}http.get(`${property.widgetDropdownControllerUrl}?$limit=${dollar}{limit}&$offset=${dollar}{++loadMoreOptions${property.name}Counter * limit}`) + .then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const resultValues = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + const newValues = []; + resultValues.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + newValues.push(e); + } + }); + newValues.forEach(e => { + if (!${dollar}scope.options${property.name}.find(o => o.value === e.value)) { + ${dollar}scope.options${property.name}.push(e); + } + }) + $scope.options${property.name}HasMore = resultValues.length > 0; + $scope.options${property.name}Loading = false; + }, (error) => { + $scope.options${property.name}Loading = false; + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }; + + $scope.onOptions${property.name}Change = (event) => { + if (allValues${property.name}.length === 0) { + allValues${property.name}.push(...${dollar}scope.options${property.name}); + } + if (event.originalEvent.target.value === '') { + allValues${property.name}.sort((a, b) => a.text.localeCompare(b.text)); + ${dollar}scope.options${property.name} = allValues${property.name}; + $scope.options${property.name}HasMore = true; + } else if (isText(event.which)) { + $scope.options${property.name}HasMore = false; + let cacheHit = false; + Array.from(lastSearchValues${property.name}).forEach(e => { + if (event.originalEvent.target.value.startsWith(e)) { + cacheHit = true; + } + }) + if (!cacheHit) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownValue}', operator: 'LIKE', value: `${dollar}{event.originalEvent.target.value}%` } + ] + }).then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const searchResult = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + searchResult.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + } + }); + ${dollar}scope.options${property.name} = allValues${property.name}.filter(e => e.text.toLowerCase().startsWith(event.originalEvent.target.value.toLowerCase())); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + lastSearchValues${property.name}.add(event.originalEvent.target.value); + } + } + }; +#end +#end + function isText(keycode) { + if ((keycode >= 48 && keycode <= 90) || (keycode >= 96 && keycode <= 111) || (keycode >= 186 && keycode <= 222) || [8, 46, 173].includes(keycode)) return true; + return false; + } +#end + +#foreach ($property in $properties) +#if($property.widgetDependsOnProperty) + ${dollar}scope.${dollar}watch('entity.${property.widgetDependsOnProperty}', (newValue, oldValue) => { + if (newValue !== undefined && newValue !== null) { + ${dollar}http.get(${dollar}scope.service${property.widgetDependsOnProperty} + '/' + newValue).then((response) => { + let valueFrom = response.data.${property.widgetDependsOnValueFrom}; +#if($property.widgetType != "DROPDOWN") + $scope.entity.${property.name} = valueFrom; +#end +#if($property.widgetType == "DROPDOWN") + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDependsOnFilterBy}', operator: 'EQ', value: valueFrom } + ] + }).then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + if ($scope.action !== 'select' && newValue !== oldValue) { + if (${dollar}scope.options${property.name}.length == 1) { + $scope.entity.${property.name} = ${dollar}scope.options${property.name}[0].value; + } else { + $scope.entity.${property.name} = undefined; + } + } + }, (error) => { + console.error(error); + }); +#end + }, (error) => { + console.error(error); + }); + } + }); + +#end +#end + $scope.alert = (message) => { + if (message) Dialogs.showAlert({ + title: description, + message: message, + type: AlertTypes.Information, + preformatted: true, + }); + }; + + $scope.cancel = () => { + $scope.entity = {}; + $scope.action = 'select'; + Dialogs.closeWindow({ id: '${name}-details' }); + }; + + $scope.clearErrorMessage = () => { + $scope.errorMessage = null; + }; + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/index.html.template new file mode 100644 index 00000000000..96e8e9b3b6e --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/index.html.template @@ -0,0 +1,576 @@ +#set($dollar = '$') + + + + + + + + + + + + + + + + + {{ errorMessage }} + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + + More Options + + + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+ #if($property.description) +
+ +
+ #end +
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end +
+ #if($property.description) +
+ +
+ #end +
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.extension.template new file mode 100644 index 00000000000..e0467a1d892 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-window/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.js.template new file mode 100644 index 00000000000..9f6c7c33bdd --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/dialog-window/view.js.template @@ -0,0 +1,17 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-details', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-window/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/index.html.template new file mode 100644 index 00000000000..41d6304554a --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/index.html.template @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + {{'$projectName:${tprefix}.defaults.items' | t}} + + + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.widgetIsMajor) + +#end +#end + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.widgetIsMajor) +#if($property.widgetType == "DROPDOWN") + +#elseif($property.widgetType == "EMAIL") + +#elseif($property.widgetType == "URL") + +#elseif($property.widgetType == "TEL") + +#elseif($property.widgetType == "COLOR") + +#elseif($property.widgetType == "WEEK") + +#elseif($property.widgetType == "MONTH") + +#elseif($property.widgetType == "TIME") + +#elseif($property.widgetType == "DATETIME-LOCAL") + +#elseif($property.widgetType == "DATE") + +#elseif($property.widgetType == "CHECKBOX") + +#else + +#end +#end +#end + + + +
{{ '$projectName:${tprefix}.t.$property.dataName' | t:'$property.name' }}
{{'$projectName:${tprefix}.messages.noData' | t}}
+ {{options${property.name}Value(next.${property.name})}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + + + + + + + + + + + + + + + {{next.${property.name}}} + + + + + + + + + + + + + +
+
+ + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/view.extension.template new file mode 100644 index 00000000000..831aabab13c --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/view.extension.template @@ -0,0 +1,10 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/view.js", +#if($type == 'SETTING') + "extensionPoint": "application-settings", +#else + "extensionPoint": "application-views", +#end + "description": "${projectName} - Application View"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/view.js.template new file mode 100644 index 00000000000..67b46fcd142 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/manage/view.js.template @@ -0,0 +1,25 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + region: 'center', +#if($type == 'SETTING') + lazyLoad: true, + autoFocusTab: false, +#else + lazyLoad: false, + autoFocusTab: true, +#end + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/controller.js.template new file mode 100644 index 00000000000..cb87a8c07d9 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/controller.js.template @@ -0,0 +1,250 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService) => { + const Dialogs = new DialogHub(); + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataOffset = 0; + $scope.dataLimit = 10; + $scope.action = 'select'; + + //-----------------Custom Actions-------------------// + Extensions.getWindows(['${projectName}-custom-action']).then((response) => { + $scope.pageActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && (e.type === 'page' || e.type === undefined)); + }); + + $scope.triggerPageAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + maxWidth: action.maxWidth, + maxHeight: action.maxHeight, + closeButton: true + }); + }; + //-----------------Custom Actions-------------------// + + function refreshData() { + $scope.dataReset = true; + $scope.dataPage--; + } + + function resetPagination() { + $scope.dataReset = true; + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 10; + } + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.clearDetails', handler: () => { + $scope.$evalAsync(() => { + $scope.selectedEntity = null; + $scope.action = 'select'; + }); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', handler: (data) => { + resetPagination(); + $scope.filter = data.filter; + $scope.filterEntity = data.entity; + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + //-----------------Events-------------------// + + $scope.loadPage = (pageNumber, filter) => { + if (!filter && $scope.filter) { + filter = $scope.filter; + } + if (!filter) { + filter = { + $filter: {} + }; + } + $scope.selectedEntity = null; + EntityService.count(filter).then((resp) => { + if (resp.data) { + $scope.dataCount = resp.data.count; + } + $scope.dataPages = Math.ceil($scope.dataCount / $scope.dataLimit); + filter.$filter.offset = ($scope.dataPage - 1) * $scope.dataLimit; + filter.$filter.limit = $scope.dataLimit; + if ($scope.dataReset) { + filter.$filter.offset = 0; + filter.$filter.limit = $scope.dataPage * $scope.dataLimit; + } + EntityService.search(filter).then((response) => { + if ($scope.data == null || $scope.dataReset) { + $scope.data = []; + $scope.dataReset = false; + } +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + if (options${property.name}HasMore) { + const options${property.name}SearchValues = Array.from(new Set(response.data.map(e => e.${property.name}))); + if (options${property.name}SearchValues.length > 0) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownKey}', operator: 'IN', value: options${property.name}SearchValues } + ] + }).then((response) => { + ${dollar}scope.options${property.name}.push(...response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + }))); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + } + } +#end +#end +#end +#if($hasDates) + response.data.forEach(e => { +#foreach ($property in $properties) +#if($property.isDateType) + if (e.${property.name}) { + e.${property.name} = new Date(e.${property.name}); + } +#end +#end + }); + +#end + ${dollar}scope.data = ${dollar}scope.data.concat(response.data); + $scope.dataPage++; + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCount', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + $scope.loadPage($scope.dataPage, $scope.filter); + + $scope.selectEntity = (entity) => { + $scope.selectedEntity = entity; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN" && $property.widgetDropDownMultiSelect) + entity.${property.name} = entity.${property.name}.split(',').map(e => parseInt(e)); +#end +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entitySelected', data: { + entity: entity, + selectedMainEntityId: entity.${primaryKeysString}, +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end + }}); + }; + + $scope.openFilter = () => { + Dialogs.showWindow({ + id: '${name}-filter', + params: { + entity: $scope.filterEntity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + } + }); + }; +#if($hasDropdowns) + + //----------------Dropdowns-----------------// +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end +#foreach ($property in $properties) +#if ($property.widgetType == "DROPDOWN") + let options${property.name}HasMore = true; + + ${dollar}http.get('${property.widgetDropdownControllerUrl}/count').then((response) => { + const options${property.name}Count = response.data.count; + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + options${property.name}HasMore = options${property.name}Count > ${dollar}scope.options${property.name}.length; + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + +#end +#end +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = (optionKey) => { +#if($property.widgetDropDownMultiSelect) + const values = []; + if (Array.isArray(optionKey)) { + optionKey = optionKey.join(); + } + optionKey.split(',').map(e => parseInt(e)).forEach(key => { + const found = ${dollar}scope.options${property.name}.find(e => e.value === key); + if (found) { + values.push(found.text); + } + }); + return values.join(', '); +#else + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; +#end + }; +#end +#end + //----------------Dropdowns-----------------// +#end + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/controller.js.template new file mode 100644 index 00000000000..6514041f993 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/controller.js.template @@ -0,0 +1,263 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', ($scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService) => { + const Dialogs = new DialogHub(); + //-----------------Custom Actions-------------------// + Extensions.getWindows(['${projectName}-custom-action']).then((response) => { + $scope.pageActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && (e.type === 'page' || e.type === undefined)); + $scope.entityActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && e.type === 'entity'); + }); + + $scope.triggerPageAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + params: { + selectedMainEntityId: $scope.selectedMainEntityId, + }, + maxWidth: action.maxWidth, + maxHeight: action.maxHeight, + closeButton: true + }); + }; + + $scope.triggerEntityAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + params: { + id: $scope.entity.${primaryKeysString}, + selectedMainEntityId: $scope.selectedMainEntityId, + }, + closeButton: true + }); + }; + //-----------------Custom Actions-------------------// + + function resetPagination() { + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 10; + } + resetPagination(); + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '#if($hasReferencedProjection)${referencedProjectionProjectName}.${referencedProjectionPerspectiveName}#else${projectName}.${perspectiveName}#end.${masterEntity}.entitySelected', handler: (data) => { + resetPagination(); + $scope.selectedMainEntityId = data.selectedMainEntityId; + $scope.loadPage($scope.dataPage); + }}); + Dialogs.addMessageListener({ topic: '#if($hasReferencedProjection)${referencedProjectionProjectName}.${referencedProjectionPerspectiveName}#else${projectName}.${perspectiveName}#end.${masterEntity}.clearDetails', handler: () => { + $scope.$evalAsync(() => { + resetPagination(); + $scope.selectedMainEntityId = null; + $scope.data = null; + }); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.clearDetails', handler: () => { + $scope.$evalAsync(() => { + $scope.entity = {}; + }); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', handler: (data) => { + resetPagination(); + $scope.filter = data.filter; + $scope.filterEntity = data.entity; + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + //-----------------Events-------------------// + + $scope.loadPage = (pageNumber, filter) => { + let ${masterEntityId} = ${dollar}scope.selectedMainEntityId; + if (!filter && $scope.filter) { + filter = $scope.filter; + } + if (!filter) { + filter = { + $filter: { + conditions: [] + } + }; + } + + filter.${dollar}filter.conditions.push({ propertyName: '${masterEntityId}', operator: 'EQ', value: ${masterEntityId} }); + $scope.dataPage = pageNumber; + EntityService.count(filter).then((resp) => { + if (resp.data) { + $scope.dataCount = resp.data.count; + } + filter.$filter.offset = (pageNumber - 1) * $scope.dataLimit; + filter.$filter.limit = $scope.dataLimit; + EntityService.search(filter).then((response) => { +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + if (options${property.name}HasMore) { + const options${property.name}SearchValues = Array.from(new Set(response.data.map(e => e.${property.name}))); + if (options${property.name}SearchValues.length > 0) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownKey}', operator: 'IN', value: options${property.name}SearchValues } + ] + }).then((response) => { + ${dollar}scope.options${property.name}.push(...response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + }))); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + } + } +#end +#end +#end +#if($hasDates) + response.data.forEach(e => { +#foreach ($property in $properties) +#if($property.isDateType) + if (e.${property.name}) { + e.${property.name} = new Date(e.${property.name}); + } +#end +#end + }); + +#end + $scope.data = response.data; + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCount', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + + $scope.selectEntity = (entity) => { + $scope.selectedEntity = entity; + }; + + $scope.openDetails = (entity) => { + $scope.selectedEntity = entity; + Dialogs.showWindow({ + id: '${name}-details', + params: { + entity: entity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + }); + }; + + $scope.openFilter = () => { + Dialogs.showWindow({ + id: '${name}-filter', + params: { + entity: $scope.filterEntity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + }); + }; +#if($hasDropdowns) + + //----------------Dropdowns-----------------// +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end +#foreach ($property in $properties) +#if ($property.widgetType == "DROPDOWN") + let options${property.name}HasMore = true; + + ${dollar}http.get('${property.widgetDropdownControllerUrl}/count').then((response) => { + const options${property.name}Count = response.data.count; + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + options${property.name}HasMore = options${property.name}Count > ${dollar}scope.options${property.name}.length; + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); +#end +#end +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = (optionKey) => { +#if($property.widgetDropDownMultiSelect) + const values = []; + if (Array.isArray(optionKey)) { + optionKey = optionKey.join(); + } + optionKey.split(',').map(e => parseInt(e)).forEach(key => { + const found = ${dollar}scope.options${property.name}.find(e => e.value === key); + if (found) { + values.push(found.text); + } + }); + return values.join(', '); +#else + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; +#end + }; +#end +#end + //----------------Dropdowns-----------------// +#end + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/controller.js.template new file mode 100644 index 00000000000..a42a66b9860 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/controller.js.template @@ -0,0 +1,203 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end ViewParameters) => { + const Dialogs = new DialogHub(); + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { +#foreach ($property in $properties) +#if($property.isDateType) + if (params?.entity?.${property.name}From) { + params.entity.${property.name}From = new Date(params.entity.${property.name}From); + } + if (params?.entity?.${property.name}To) { + params.entity.${property.name}To = new Date(params.entity.${property.name}To); + } +#end +#end + $scope.entity = params.entity ?? {}; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } + + $scope.filter = () => { + let entity = $scope.entity; + const filter = { + $filter: { + conditions: [], + sorts: [], + limit: 20, + offset: 0 + } + }; +#foreach ($property in $properties) +#if($property.dataTypeTypescript == 'number') + if (entity.${property.name} !== undefined) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'boolean') + if (entity.${property.name} !== undefined && entity.is${property.name}Indeterminate === false) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'string') + if (entity.${property.name}) { + const condition = { propertyName: '${property.name}', operator: 'LIKE', value: `%$dollar{entity.${property.name}}%` }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'Date') + if (entity.${property.name}From) { + const condition = { propertyName: '${property.name}', operator: 'GE', value: entity.${property.name}From }; + filter.$filter.conditions.push(condition); + } + if (entity.${property.name}To) { + const condition = { propertyName: '${property.name}', operator: 'LE', value: entity.${property.name}To }; + filter.$filter.conditions.push(condition); + } +#end +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', data: { + entity: entity, + filter: filter + }}); + $scope.cancel(); + }; + + $scope.resetFilter = () => { + $scope.entity = {}; + $scope.filter(); +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + lastSearchValues${property.name}.clear(); + allValues${property.name}.length = 0; +#end +#end +#end + }; + + $scope.cancel = () => { + Dialogs.closeWindow({ id: '${name}-filter' }); + }; + + $scope.clearErrorMessage = () => { + $scope.errorMessage = null; + }; + +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const lastSearchValues${property.name} = new Set(); + const allValues${property.name} = []; + let loadMoreOptions${property.name}Counter = 0; + $scope.options${property.name}Loading = false; + $scope.options${property.name}HasMore = true; + + $scope.loadMoreOptions${property.name} = () => { + const limit = 20; + $scope.options${property.name}Loading = true; + ${dollar}http.get(`${property.widgetDropdownControllerUrl}?$limit=${dollar}{limit}&$offset=${dollar}{++loadMoreOptions${property.name}Counter * limit}`) + .then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const resultValues = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + const newValues = []; + resultValues.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + newValues.push(e); + } + }); + newValues.forEach(e => { + if (!${dollar}scope.options${property.name}.find(o => o.value === e.value)) { + ${dollar}scope.options${property.name}.push(e); + } + }) + $scope.options${property.name}HasMore = resultValues.length > 0; + $scope.options${property.name}Loading = false; + }, (error) => { + $scope.options${property.name}Loading = false; + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }; + + $scope.onOptions${property.name}Change = (event) => { + if (allValues${property.name}.length === 0) { + allValues${property.name}.push(...${dollar}scope.options${property.name}); + } + if (event.originalEvent.target.value === '') { + allValues${property.name}.sort((a, b) => a.text.localeCompare(b.text)); + ${dollar}scope.options${property.name} = allValues${property.name}; + $scope.options${property.name}HasMore = true; + } else if (isText(event.which)) { + $scope.options${property.name}HasMore = false; + let cacheHit = false; + Array.from(lastSearchValues${property.name}).forEach(e => { + if (event.originalEvent.target.value.startsWith(e)) { + cacheHit = true; + } + }) + if (!cacheHit) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownValue}', operator: 'LIKE', value: `${dollar}{event.originalEvent.target.value}%` } + ] + }).then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const searchResult = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + searchResult.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + } + }); + ${dollar}scope.options${property.name} = allValues${property.name}.filter(e => e.text.toLowerCase().startsWith(event.originalEvent.target.value.toLowerCase())); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + lastSearchValues${property.name}.add(event.originalEvent.target.value); + } + } + }; + +#end +#end + function isText(keycode) { + if ((keycode >= 48 && keycode <= 90) || (keycode >= 96 && keycode <= 111) || (keycode >= 186 && keycode <= 222) || [8, 46, 173].includes(keycode)) return true; + return false; + } + +#end +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/index.html.template new file mode 100644 index 00000000000..7a9332b0a48 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/index.html.template @@ -0,0 +1,336 @@ +#set($dollar = '$') + + + + + + + + + + + + + + + + {{ errorMessage }} + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.name != $masterEntityId) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + + More Options + + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/view.extension.template new file mode 100644 index 00000000000..d9523eb789b --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/dialog-filter/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/view.js.template new file mode 100644 index 00000000000..315217d3cff --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-filter/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-filter', + label: '${name} Filter', + translation: { + key: '$projectName:${tprefix}.extName', + options: { + content: '$t($projectName:${tprefix}.t.$dataName) $t($projectName:${tprefix}.defaults.filter)', + } + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/dialog-filter/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/controller.js.template new file mode 100644 index 00000000000..fa1112e0532 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/controller.js.template @@ -0,0 +1,36 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, ViewParameters) => { + $scope.entity = {}; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { +#if($hasDates) + +#foreach ($property in $properties) +#if($property.isDateType) + if (params.entity.${property.name}) { + params.entity.${property.name} = new Date(params.entity.${property.name}); + } +#end +#end +#end + + $scope.entity = params.entity; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}?.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end +#end + } +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/index.html.template new file mode 100644 index 00000000000..f63d4fb9d64 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/index.html.template @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.relationshipType != "COMPOSITION") +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#end +#end +#end +
+
+
+ + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/view.extension.template new file mode 100644 index 00000000000..ce739c305e7 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/dialog-window/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/view.js.template new file mode 100644 index 00000000000..83ee2a40aad --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/dialog-window/view.js.template @@ -0,0 +1,17 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-details', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/dialog-window/index.html', + perspectiveName: '#if($hasReferencedProjection)${referencedProjectionPerspectiveName}#else${perspectiveName}#end' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/index.html.template new file mode 100644 index 00000000000..b371e016a1e --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/index.html.template @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + {{'$projectName:${tprefix}.messages.detailSelectRecord' | t}} + + + + {{'$projectName:${tprefix}.defaults.items' | t}} + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.widgetIsMajor) + +#end +#end + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.widgetIsMajor) +#if($property.widgetType == "DROPDOWN") + +#elseif($property.widgetType == "EMAIL") + +#elseif($property.widgetType == "URL") + +#elseif($property.widgetType == "TEL") + +#elseif($property.widgetType == "COLOR") + +#elseif($property.widgetType == "WEEK") + +#elseif($property.widgetType == "MONTH") + +#elseif($property.widgetType == "TIME") + +#elseif($property.widgetType == "DATETIME-LOCAL") + +#elseif($property.widgetType == "DATE") + +#elseif($property.widgetType == "CHECKBOX") + +#else + +#end +#end +#end + + + +
{{ '$projectName:${tprefix}.t.$property.dataName' | t:'$property.name' }}
{{'$projectName:${tprefix}.messages.noData' | t}}
+ {{options${property.name}Value(next.${property.name})}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + + + + + + + + + + + + + + + {{next.${property.name}}} + + + + + + + + + + + +
+
+ + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/view.extension.template new file mode 100644 index 00000000000..4f6c51e52dd --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/view.js", + "extensionPoint": "application-views", + "description": "${projectName} - Application View - Details"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/view.js.template new file mode 100644 index 00000000000..30d6da8dc27 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/detail/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + region: 'bottom', + lazyLoad: false, + autoFocusTab: true, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/index.html', + perspectiveName: '#if($hasReferencedProjection)${referencedProjectionPerspectiveName}#else${perspectiveName}#end' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/controller.js.template new file mode 100644 index 00000000000..ba2093a6411 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/controller.js.template @@ -0,0 +1,204 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end ViewParameters) => { + const Dialogs = new DialogHub(); + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { +#foreach ($property in $properties) +#if($property.isDateType) + if (params?.entity?.${property.name}From) { + params.entity.${property.name}From = new Date(params.entity.${property.name}From); + } + if (params?.entity?.${property.name}To) { + params.entity.${property.name}To = new Date(params.entity.${property.name}To); + } +#end +#end + $scope.entity = params.entity ?? {}; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } + + $scope.filter = () => { + let entity = $scope.entity; + const filter = { + $filter: { + conditions: [], + sorts: [], + limit: 20, + offset: 0 + } + }; +#foreach ($property in $properties) +#if($property.dataTypeTypescript == 'number') + if (entity.${property.name} !== undefined) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'boolean') + if (entity.${property.name} !== undefined && entity.is${property.name}Indeterminate === false) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'string') + if (entity.${property.name}) { + const condition = { propertyName: '${property.name}', operator: 'LIKE', value: `%$dollar{entity.${property.name}}%` }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'Date') + if (entity.${property.name}From) { + const condition = { propertyName: '${property.name}', operator: 'GE', value: entity.${property.name}From }; + filter.$filter.conditions.push(condition); + } + if (entity.${property.name}To) { + const condition = { propertyName: '${property.name}', operator: 'LE', value: entity.${property.name}To }; + filter.$filter.conditions.push(condition); + } +#end +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', data: { + entity: entity, + filter: filter + }}); + Dialogs.triggerEvent('${projectName}.${perspectiveName}.${name}.clearDetails'); + $scope.cancel(); + }; + + $scope.resetFilter = () => { + $scope.entity = {}; + $scope.filter(); +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + lastSearchValues${property.name}.clear(); + allValues${property.name}.length = 0; +#end +#end +#end + }; + + $scope.cancel = () => { + Dialogs.closeWindow({ id: '${name}-filter' }); + }; + + $scope.clearErrorMessage = () => { + $scope.errorMessage = null; + }; + +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const lastSearchValues${property.name} = new Set(); + const allValues${property.name} = []; + let loadMoreOptions${property.name}Counter = 0; + $scope.options${property.name}Loading = false; + $scope.options${property.name}HasMore = true; + + $scope.loadMoreOptions${property.name} = () => { + const limit = 20; + $scope.options${property.name}Loading = true; + ${dollar}http.get(`${property.widgetDropdownControllerUrl}?$limit=${dollar}{limit}&$offset=${dollar}{++loadMoreOptions${property.name}Counter * limit}`) + .then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const resultValues = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + const newValues = []; + resultValues.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + newValues.push(e); + } + }); + newValues.forEach(e => { + if (!${dollar}scope.options${property.name}.find(o => o.value === e.value)) { + ${dollar}scope.options${property.name}.push(e); + } + }) + $scope.options${property.name}HasMore = resultValues.length > 0; + $scope.options${property.name}Loading = false; + }, (error) => { + $scope.options${property.name}Loading = false; + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }; + + $scope.onOptions${property.name}Change = (event) => { + if (allValues${property.name}.length === 0) { + allValues${property.name}.push(...${dollar}scope.options${property.name}); + } + if (event.originalEvent.target.value === '') { + allValues${property.name}.sort((a, b) => a.text.localeCompare(b.text)); + ${dollar}scope.options${property.name} = allValues${property.name}; + $scope.options${property.name}HasMore = true; + } else if (isText(event.which)) { + $scope.options${property.name}HasMore = false; + let cacheHit = false; + Array.from(lastSearchValues${property.name}).forEach(e => { + if (event.originalEvent.target.value.startsWith(e)) { + cacheHit = true; + } + }) + if (!cacheHit) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownValue}', operator: 'LIKE', value: `${dollar}{event.originalEvent.target.value}%` } + ] + }).then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const searchResult = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + searchResult.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + } + }); + ${dollar}scope.options${property.name} = allValues${property.name}.filter(e => e.text.toLowerCase().startsWith(event.originalEvent.target.value.toLowerCase())); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + lastSearchValues${property.name}.add(event.originalEvent.target.value); + } + } + }; + +#end +#end + function isText(keycode) { + if ((keycode >= 48 && keycode <= 90) || (keycode >= 96 && keycode <= 111) || (keycode >= 186 && keycode <= 222) || [8, 46, 173].includes(keycode)) return true; + return false; + } + +#end +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/index.html.template new file mode 100644 index 00000000000..fce038b8a79 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/index.html.template @@ -0,0 +1,336 @@ +#set($dollar = '$') + + + + + + + + + + + + + + + + {{ errorMessage }} + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + + More Options + + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/view.extension.template new file mode 100644 index 00000000000..8b596562b61 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-filter/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/view.js.template new file mode 100644 index 00000000000..3a25b9a3a55 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-filter/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-filter', + label: '${name} Filter', + translation: { + key: '$projectName:${tprefix}.extName', + options: { + content: '$t($projectName:${tprefix}.t.$dataName) $t($projectName:${tprefix}.defaults.filter)', + } + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-filter/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/controller.js.template new file mode 100644 index 00000000000..924391a6ad9 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/controller.js.template @@ -0,0 +1,30 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, ViewParameters) => { + $scope.entity = {}; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { + $scope.action = 'select'; + +#foreach ($property in $properties) +#if($property.isDateType) + if (params.entity.${property.name}) { + params.entity.${property.name} = new Date(params.entity.${property.name}); + } +#end +#end + $scope.entity = params.entity; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}?.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/index.html.template new file mode 100644 index 00000000000..fe33641fc95 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/index.html.template @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#end +#end +#end +
+
+
+ + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/view.extension.template new file mode 100644 index 00000000000..e0467a1d892 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-window/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/view.js.template new file mode 100644 index 00000000000..eecaced6c61 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/dialog-window/view.js.template @@ -0,0 +1,27 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-details', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-window/index.html', + perspectiveName: '${perspectiveName}', +#if($perspectiveRole || $roleRead) + roles: [ +#if($perspectiveRole) + '${perspectiveRole}', +#end +#if($roleRead) + '${roleRead}', +#end + ] +#end +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/index.html.template new file mode 100644 index 00000000000..9889a75d0a9 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/index.html.template @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + {{'$projectName:${tprefix}.defaults.items' | t}} + + + + + + + + + + + + + + + + + + +#elseif($masterProperties.title.widgetType == "DATE") + item-title="{{next.${masterProperties.title.name} | date: 'dd/MMM/yyyy'}}"> +#elseif($masterProperties.title.widgetType == "DATETIME-LOCAL") + item-title="{{next.${masterProperties.title.name} | date: 'dd/MMM/yyyy HH:MM'}}"> +#elseif($masterProperties.title.widgetType == "TIME") + item-title="{{next.${masterProperties.title.name} | date: 'HH:MM:ss'}}"> +#elseif($masterProperties.title.widgetType == "WEEK") + item-title="Week {{next.${masterProperties.title.name} | date: 'ww'}}"> +#else + item-title="{{next.${masterProperties.title.name}}}"> +#end + +#foreach ($property in $masterProperties.properties) +#if($property.widgetType == "DROPDOWN") + {{options${property.name}Value(next.${property.name})}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "DATE") + {{next.${property.name} | date: "dd/MMM/yyyy"}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "DATETIME-LOCAL") + {{next.${property.name} | date: "dd/MMM/yyyy HH:MM"}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "TIME") + {{next.${property.name} | date: "HH:MM:ss"}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "WEEK") + Week {{next.${property.name} | date: "ww"}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "EMAIL") + {{next.${property.name}}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "URL") + {{next.${property.name}}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "TEL") + {{next.${property.name}}}#if(!$foreach.isLast()) |#end +#else + {{next.${property.name}}}#if(!$foreach.isLast()) |#end +#end +#end + + + + + + + {{ '$projectName:${tprefix}.defaults.loadMore' | t }} + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/controller.js.template new file mode 100644 index 00000000000..9edb2232f65 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/controller.js.template @@ -0,0 +1,57 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, Extensions, LocaleService) => { + const Dialogs = new DialogHub(); + $scope.entity = {}; + + //-----------------Custom Actions-------------------// + Extensions.getWindows(['${projectName}-custom-action']).then((response) => { + $scope.entityActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && e.type === 'entity'); + }); + + $scope.triggerEntityAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + params: { + id: $scope.entity.${primaryKeysString} + }, + closeButton: true, + }); + }; + //-----------------Custom Actions-------------------// + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.clearDetails', handler: () => { + $scope.$evalAsync(() => { + $scope.entity = {}; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end + }); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entitySelected', handler: (data) => { + $scope.$evalAsync(() => { +#foreach ($property in $properties) +#if($property.isDateType) + if (data.entity.${property.name}) { + data.entity.${property.name} = new Date(data.entity.${property.name}); + } +#end +#end + $scope.entity = data.entity; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = data.options${property.name}; +#end +#end + }); + }}); + //-----------------Events-------------------// + + $scope.cancel = () => { + Dialogs.triggerEvent('${projectName}.${perspectiveName}.${name}.clearDetails'); + }; +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/index.html.template new file mode 100644 index 00000000000..1c0f344529d --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/index.html.template @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#end +#end +#end +
+
+
+ + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/view.extension.template new file mode 100644 index 00000000000..2eaa6ee3f86 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/main-details/view.js", + "extensionPoint": "application-views", + "description": "${projectName} - Application View - Main Details"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/view.js.template new file mode 100644 index 00000000000..87de655838a --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/main-details/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-details', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + region: 'center', + lazyLoad: false, + autoFocusTab: true, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/main-details/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/view.extension.template new file mode 100644 index 00000000000..f9ae92d4291 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/view.js", + "extensionPoint": "application-views", + "description": "${projectName} - Application View"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/view.js.template new file mode 100644 index 00000000000..a3927b88432 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-list/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + region: 'left', + lazyLoad: false, + autoFocusTab: false, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/controller.js.template new file mode 100644 index 00000000000..ba8c842cebe --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/controller.js.template @@ -0,0 +1,336 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', ($scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService, ButtonStates) => { + const Dialogs = new DialogHub(); + let translated = { + yes: 'Yes', + no: 'No', + deleteConfirm: 'Are you sure you want to delete ${name}? This action cannot be undone.', + deleteTitle: 'Delete ${name}?' + }; + + LocaleService.onInit(() => { + translated.yes = LocaleService.t('$projectName:${tprefix}.defaults.yes'); + translated.no = LocaleService.t('$projectName:${tprefix}.defaults.no'); + translated.deleteTitle = LocaleService.t('$projectName:${tprefix}.defaults.deleteTitle', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + translated.deleteConfirm = LocaleService.t('$projectName:${tprefix}.messages.deleteConfirm', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + }); + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataOffset = 0; + $scope.dataLimit = 10; + $scope.action = 'select'; + + //-----------------Custom Actions-------------------// + Extensions.getWindows(['${projectName}-custom-action']).then((response) => { + $scope.pageActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && (e.type === 'page' || e.type === undefined)); + }); + + $scope.triggerPageAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + maxWidth: action.maxWidth, + maxHeight: action.maxHeight, + closeButton: true + }); + }; + //-----------------Custom Actions-------------------// + + function refreshData() { + $scope.dataReset = true; + $scope.dataPage--; + } + + function resetPagination() { + $scope.dataReset = true; + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 10; + } + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.clearDetails', handler: () => { + $scope.$evalAsync(() => { + $scope.selectedEntity = null; + $scope.action = 'select'; + }); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entityCreated', handler: () => { + refreshData(); + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entityUpdated', handler: () => { + refreshData(); + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', handler: (data) => { + resetPagination(); + $scope.filter = data.filter; + $scope.filterEntity = data.entity; + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + //-----------------Events-------------------// + + $scope.loadPage = (pageNumber, filter) => { + if (!filter && $scope.filter) { + filter = $scope.filter; + } + if (!filter) { + filter = { + $filter: {} + }; + } + $scope.selectedEntity = null; + EntityService.count(filter).then((resp) => { + if (resp.data) { + $scope.dataCount = resp.data.count; + } + $scope.dataPages = Math.ceil($scope.dataCount / $scope.dataLimit); + filter.$filter.offset = ($scope.dataPage - 1) * $scope.dataLimit; + filter.$filter.limit = $scope.dataLimit; + if ($scope.dataReset) { + filter.$filter.offset = 0; + filter.$filter.limit = $scope.dataPage * $scope.dataLimit; + } + + EntityService.search(filter).then((response) => { + if ($scope.data == null || $scope.dataReset) { + $scope.data = []; + $scope.dataReset = false; + } +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + if (options${property.name}HasMore) { + const options${property.name}SearchValues = Array.from(new Set(response.data.map(e => e.${property.name}))); + if (options${property.name}SearchValues.length > 0) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownKey}', operator: 'IN', value: options${property.name}SearchValues } + ] + }).then((response) => { + ${dollar}scope.options${property.name}.push(...response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + }))); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + } + } +#end +#end +#end +#if($hasDates) + response.data.forEach(e => { +#foreach ($property in $properties) +#if($property.isDateType) + if (e.${property.name}) { + e.${property.name} = new Date(e.${property.name}); + } +#end +#end + }); + +#end + ${dollar}scope.data = ${dollar}scope.data.concat(response.data); + $scope.dataPage++; + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCount', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + $scope.loadPage($scope.dataPage, $scope.filter); + + $scope.selectEntity = (entity) => { + $scope.selectedEntity = entity; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN" && $property.widgetDropDownMultiSelect) + entity.${property.name} = entity.${property.name}.split(',').map(e => parseInt(e)); +#end +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entitySelected', data: { + entity: entity, + selectedMainEntityId: entity.${primaryKeysString}, +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end + }}); + }; + + $scope.createEntity = () => { + $scope.selectedEntity = null; + $scope.action = 'create'; + +#if($hasDropdowns) + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.createEntity', data: { + entity: {}, +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end + }}); +#else + Dialogs.triggerEvent('${projectName}.${perspectiveName}.${name}.createEntity'); +#end + }; + + $scope.updateEntity = () => { + $scope.action = 'update'; + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.updateEntity', data: { + entity: $scope.selectedEntity, +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end + }}); + }; + + $scope.deleteEntity = () => { + let id = ${dollar}scope.selectedEntity.${primaryKeysString}; + Dialogs.showDialog({ + title: translated.deleteTitle, + message: translated.deleteConfirm, + buttons: [{ + id: 'delete-btn-yes', + state: ButtonStates.Emphasized, + label: translated.yes, + }, { + id: 'delete-btn-no', + label: translated.no, + }], + closeButton: false + }).then((buttonId) => { + if (buttonId === 'delete-btn-yes') { + EntityService.delete(id).then(() => { + refreshData(); + $scope.loadPage($scope.dataPage, $scope.filter); + Dialogs.triggerEvent('${projectName}.${perspectiveName}.${name}.clearDetails'); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToDelete', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + } + }); + }; + + $scope.openFilter = () => { + Dialogs.showWindow({ + id: '${name}-filter', + params: { + entity: $scope.filterEntity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + }); + }; +#if($hasDropdowns) + + //----------------Dropdowns-----------------// +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end + +#foreach ($property in $properties) +#if ($property.widgetType == "DROPDOWN") + let options${property.name}HasMore = true; + + ${dollar}http.get('${property.widgetDropdownControllerUrl}/count').then((response) => { + const options${property.name}Count = response.data.count; + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + options${property.name}HasMore = options${property.name}Count > ${dollar}scope.options${property.name}.length; + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); +#end +#end + +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = (optionKey) => { +#if($property.widgetDropDownMultiSelect) + const values = []; + if (Array.isArray(optionKey)) { + optionKey = optionKey.join(); + } + optionKey.split(',').map(e => parseInt(e)).forEach(key => { + const found = ${dollar}scope.options${property.name}.find(e => e.value === key); + if (found) { + values.push(found.text); + } + }); + return values.join(', '); +#else + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; +#end + }; +#end +#end + //----------------Dropdowns-----------------// +#end + }); diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/controller.js.template new file mode 100644 index 00000000000..00f1d1fd1d9 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/controller.js.template @@ -0,0 +1,361 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', ($scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService, ButtonStates) => { + const Dialogs = new DialogHub(); + let translated = { + yes: 'Yes', + no: 'No', + deleteConfirm: 'Are you sure you want to delete ${name}? This action cannot be undone.', + deleteTitle: 'Delete ${name}?' + }; + + LocaleService.onInit(() => { + translated.yes = LocaleService.t('$projectName:${tprefix}.defaults.yes'); + translated.no = LocaleService.t('$projectName:${tprefix}.defaults.no'); + translated.deleteTitle = LocaleService.t('$projectName:${tprefix}.defaults.deleteTitle', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + translated.deleteConfirm = LocaleService.t('$projectName:${tprefix}.messages.deleteConfirm', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + }); + //-----------------Custom Actions-------------------// + Extensions.getWindows(['${projectName}-custom-action']).then((response) => { + $scope.pageActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && (e.type === 'page' || e.type === undefined)); + $scope.entityActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && e.type === 'entity'); + }); + + $scope.triggerPageAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + params: { + selectedMainEntityKey: '${masterEntityId}', + selectedMainEntityId: $scope.selectedMainEntityId, + }, + maxWidth: action.maxWidth, + maxHeight: action.maxHeight, + closeButton: true + }); + }; + + $scope.triggerEntityAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + params: { + id: $scope.entity.${primaryKeysString}, + selectedMainEntityKey: '${masterEntityId}', + selectedMainEntityId: $scope.selectedMainEntityId, + }, + closeButton: true + }); + }; + //-----------------Custom Actions-------------------// + + function resetPagination() { + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 10; + } + resetPagination(); + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '#if($hasReferencedProjection)${referencedProjectionProjectName}.${referencedProjectionPerspectiveName}#else${projectName}.${perspectiveName}#end.${masterEntity}.entitySelected', handler: (data) => { + resetPagination(); + $scope.selectedMainEntityId = data.selectedMainEntityId; + $scope.loadPage($scope.dataPage); + }}); + Dialogs.addMessageListener({ topic: '#if($hasReferencedProjection)${referencedProjectionProjectName}.${referencedProjectionPerspectiveName}#else${projectName}.${perspectiveName}#end.${masterEntity}.clearDetails', handler: () => { + $scope.$evalAsync(() => { + resetPagination(); + $scope.selectedMainEntityId = null; + $scope.data = null; + }); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.clearDetails', handler: () => { + $scope.$evalAsync(() => { + $scope.entity = {}; + $scope.action = 'select'; + }); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entityCreated', handler: () => { + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entityUpdated', handler: () => { + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', handler: (data) => { + resetPagination(); + $scope.filter = data.filter; + $scope.filterEntity = data.entity; + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + //-----------------Events-------------------// + + $scope.loadPage = (pageNumber, filter) => { + let ${masterEntityId} = ${dollar}scope.selectedMainEntityId; + $scope.dataPage = pageNumber; + if (!filter && $scope.filter) { + filter = $scope.filter; + } + if (!filter) { + filter = { + $filter: { + conditions: [] + } + }; + } + filter.${dollar}filter.conditions.push({ propertyName: '${masterEntityId}', operator: 'EQ', value: ${masterEntityId} }); + EntityService.count(filter).then((resp) => { + if (resp.data) { + $scope.dataCount = resp.data.count; + } + filter.$filter.offset = (pageNumber - 1) * $scope.dataLimit; + filter.$filter.limit = $scope.dataLimit; + EntityService.search(filter).then((response) => { +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + if (options${property.name}HasMore) { + const options${property.name}SearchValues = Array.from(new Set(response.data.map(e => e.${property.name}))); + if (options${property.name}SearchValues.length > 0) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownKey}', operator: 'IN', value: options${property.name}SearchValues } + ] + }).then((response) => { + ${dollar}scope.options${property.name}.push(...response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + }))); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + } + } +#end +#end +#end +#if($hasDates) + response.data.forEach(e => { +#foreach ($property in $properties) +#if($property.isDateType) + if (e.${property.name}) { + e.${property.name} = new Date(e.${property.name}); + } +#end +#end + }); + +#end + $scope.data = response.data; + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCount', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + + $scope.selectEntity = (entity) => { + $scope.selectedEntity = entity; + }; + + $scope.openDetails = (entity) => { + $scope.selectedEntity = entity; + Dialogs.showWindow({ + id: '${name}-details', + params: { + action: 'select', + entity: entity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + }); + }; + + $scope.openFilter = () => { + Dialogs.showWindow({ + id: '${name}-filter', + params: { + entity: $scope.filterEntity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + }); + }; + + $scope.createEntity = () => { + $scope.selectedEntity = null; + Dialogs.showWindow({ + id: '${name}-details', + params: { + action: 'create', + entity: { + '${masterEntityId}': $scope.selectedMainEntityId + }, + selectedMainEntityKey: '${masterEntityId}', + selectedMainEntityId: $scope.selectedMainEntityId, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + closeButton: false + }); + }; + + $scope.updateEntity = (entity) => { + Dialogs.showWindow({ + id: '${name}-details', + params: { + action: 'update', + entity: entity, + selectedMainEntityKey: '${masterEntityId}', + selectedMainEntityId: $scope.selectedMainEntityId, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end }, + closeButton: false + }); + }; + + $scope.deleteEntity = (entity) => { + let id = entity.${primaryKeysString}; + Dialogs.showDialog({ + title: translated.deleteTitle, + message: translated.deleteConfirm, + buttons: [{ + id: 'delete-btn-yes', + state: ButtonStates.Emphasized, + label: translated.yes, + }, { + id: 'delete-btn-no', + label: translated.no, + }], + closeButton: false + }).then((buttonId) => { + if (buttonId === 'delete-btn-yes') { + EntityService.delete(id).then(() => { + $scope.loadPage($scope.dataPage, $scope.filter); + Dialogs.triggerEvent('${projectName}.${perspectiveName}.${name}.clearDetails'); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToDelete', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error, + }); + console.error('EntityService:', error); + }); + } + }); + }; +#if($hasDropdowns) + + //----------------Dropdowns-----------------// +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end + +#foreach ($property in $properties) +#if ($property.widgetType == "DROPDOWN") + let options${property.name}HasMore = true; + + ${dollar}http.get('${property.widgetDropdownControllerUrl}/count').then((response) => { + const options${property.name}Count = response.data.count; + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + options${property.name}HasMore = options${property.name}Count > ${dollar}scope.options${property.name}.length; + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); +#end +#end + +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = function (optionKey) { +#if($property.widgetDropDownMultiSelect) + const values = []; + if (Array.isArray(optionKey)) { + optionKey = optionKey.join(); + } + optionKey.split(',').map(e => parseInt(e)).forEach(key => { + const found = ${dollar}scope.options${property.name}.find(e => e.value === key); + if (found) { + values.push(found.text); + } + }); + return values.join(', '); +#else + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; +#end + }; +#end +#end + //----------------Dropdowns-----------------// +#end + }); diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/controller.js.template new file mode 100644 index 00000000000..a42a66b9860 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/controller.js.template @@ -0,0 +1,203 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end ViewParameters) => { + const Dialogs = new DialogHub(); + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { +#foreach ($property in $properties) +#if($property.isDateType) + if (params?.entity?.${property.name}From) { + params.entity.${property.name}From = new Date(params.entity.${property.name}From); + } + if (params?.entity?.${property.name}To) { + params.entity.${property.name}To = new Date(params.entity.${property.name}To); + } +#end +#end + $scope.entity = params.entity ?? {}; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } + + $scope.filter = () => { + let entity = $scope.entity; + const filter = { + $filter: { + conditions: [], + sorts: [], + limit: 20, + offset: 0 + } + }; +#foreach ($property in $properties) +#if($property.dataTypeTypescript == 'number') + if (entity.${property.name} !== undefined) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'boolean') + if (entity.${property.name} !== undefined && entity.is${property.name}Indeterminate === false) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'string') + if (entity.${property.name}) { + const condition = { propertyName: '${property.name}', operator: 'LIKE', value: `%$dollar{entity.${property.name}}%` }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'Date') + if (entity.${property.name}From) { + const condition = { propertyName: '${property.name}', operator: 'GE', value: entity.${property.name}From }; + filter.$filter.conditions.push(condition); + } + if (entity.${property.name}To) { + const condition = { propertyName: '${property.name}', operator: 'LE', value: entity.${property.name}To }; + filter.$filter.conditions.push(condition); + } +#end +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', data: { + entity: entity, + filter: filter + }}); + $scope.cancel(); + }; + + $scope.resetFilter = () => { + $scope.entity = {}; + $scope.filter(); +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + lastSearchValues${property.name}.clear(); + allValues${property.name}.length = 0; +#end +#end +#end + }; + + $scope.cancel = () => { + Dialogs.closeWindow({ id: '${name}-filter' }); + }; + + $scope.clearErrorMessage = () => { + $scope.errorMessage = null; + }; + +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const lastSearchValues${property.name} = new Set(); + const allValues${property.name} = []; + let loadMoreOptions${property.name}Counter = 0; + $scope.options${property.name}Loading = false; + $scope.options${property.name}HasMore = true; + + $scope.loadMoreOptions${property.name} = () => { + const limit = 20; + $scope.options${property.name}Loading = true; + ${dollar}http.get(`${property.widgetDropdownControllerUrl}?$limit=${dollar}{limit}&$offset=${dollar}{++loadMoreOptions${property.name}Counter * limit}`) + .then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const resultValues = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + const newValues = []; + resultValues.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + newValues.push(e); + } + }); + newValues.forEach(e => { + if (!${dollar}scope.options${property.name}.find(o => o.value === e.value)) { + ${dollar}scope.options${property.name}.push(e); + } + }) + $scope.options${property.name}HasMore = resultValues.length > 0; + $scope.options${property.name}Loading = false; + }, (error) => { + $scope.options${property.name}Loading = false; + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }; + + $scope.onOptions${property.name}Change = (event) => { + if (allValues${property.name}.length === 0) { + allValues${property.name}.push(...${dollar}scope.options${property.name}); + } + if (event.originalEvent.target.value === '') { + allValues${property.name}.sort((a, b) => a.text.localeCompare(b.text)); + ${dollar}scope.options${property.name} = allValues${property.name}; + $scope.options${property.name}HasMore = true; + } else if (isText(event.which)) { + $scope.options${property.name}HasMore = false; + let cacheHit = false; + Array.from(lastSearchValues${property.name}).forEach(e => { + if (event.originalEvent.target.value.startsWith(e)) { + cacheHit = true; + } + }) + if (!cacheHit) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownValue}', operator: 'LIKE', value: `${dollar}{event.originalEvent.target.value}%` } + ] + }).then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const searchResult = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + searchResult.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + } + }); + ${dollar}scope.options${property.name} = allValues${property.name}.filter(e => e.text.toLowerCase().startsWith(event.originalEvent.target.value.toLowerCase())); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + lastSearchValues${property.name}.add(event.originalEvent.target.value); + } + } + }; + +#end +#end + function isText(keycode) { + if ((keycode >= 48 && keycode <= 90) || (keycode >= 96 && keycode <= 111) || (keycode >= 186 && keycode <= 222) || [8, 46, 173].includes(keycode)) return true; + return false; + } + +#end +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/index.html.template new file mode 100644 index 00000000000..8fc43c68236 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/index.html.template @@ -0,0 +1,336 @@ +#set($dollar = '$') + + + + + + + + + + + + + + + + {{ errorMessage }} + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.name != $masterEntityId) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + + More Options + + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/view.extension.template new file mode 100644 index 00000000000..d9523eb789b --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/dialog-filter/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/view.js.template new file mode 100644 index 00000000000..315217d3cff --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-filter/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-filter', + label: '${name} Filter', + translation: { + key: '$projectName:${tprefix}.extName', + options: { + content: '$t($projectName:${tprefix}.t.$dataName) $t($projectName:${tprefix}.defaults.filter)', + } + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/dialog-filter/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/controller.js.template new file mode 100644 index 00000000000..a3c8c2a9df9 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/controller.js.template @@ -0,0 +1,278 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', ($scope, ${dollar}http, ViewParameters, LocaleService, EntityService) => { + const Dialogs = new DialogHub(); + const Notifications = new NotificationHub(); + let description = 'Description'; + let propertySuccessfullyCreated = '${name} successfully created'; + let propertySuccessfullyUpdated = '${name} successfully updated'; + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + $scope.formHeaders = { + select: '${name} Details', + create: 'Create ${name}', + update: 'Update ${name}' + }; + $scope.action = 'select'; + + LocaleService.onInit(() => { + description = LocaleService.t('$projectName:${tprefix}.defaults.description'); + $scope.formHeaders.select = LocaleService.t('$projectName:${tprefix}.defaults.formHeadSelect', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + $scope.formHeaders.create = LocaleService.t('$projectName:${tprefix}.defaults.formHeadCreate', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + $scope.formHeaders.update = LocaleService.t('$projectName:${tprefix}.defaults.formHeadUpdate', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + propertySuccessfullyCreated = LocaleService.t('$projectName:${tprefix}.messages.propertySuccessfullyCreated', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + propertySuccessfullyUpdated = LocaleService.t('$projectName:${tprefix}.messages.propertySuccessfullyUpdated', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + }); + + let params = ViewParameters.get(); + if (Object.keys(params).length) { + $scope.action = params.action; +#if($hasDates) + +#foreach ($property in $properties) +#if($property.isDateType) + if (params.entity.${property.name}) { + params.entity.${property.name} = new Date(params.entity.${property.name}); + } +#end +#end +#end + $scope.entity = params.entity; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}?.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end +#end + } + + $scope.create = () => { + let entity = $scope.entity; + entity[$scope.selectedMainEntityKey] = $scope.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN" && $property.widgetDropDownMultiSelect) + if (entity.${property.name}) { + entity.${property.name} = entity.${property.name}.join(); + } +#end +#end + EntityService.create(entity).then((response) => { + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entityCreated', data: response.data }); + Notifications.show({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + description: propertySuccessfullyCreated, + type: 'positive' + }); + $scope.cancel(); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCreate', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + + $scope.update = () => { + let id = ${dollar}scope.entity.${primaryKeysString}; + let entity = $scope.entity; + entity[$scope.selectedMainEntityKey] = $scope.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN" && $property.widgetDropDownMultiSelect) + if (entity.${property.name}) { + entity.${property.name} = entity.${property.name}.join(); + } +#end +#end + EntityService.update(id, entity).then((response) => { + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entityUpdated', data: response.data }); + Notifications.show({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + description: propertySuccessfullyUpdated, + type: 'positive' + }); + $scope.cancel(); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToUpdate', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + +#if($hasDropdowns) +#foreach ($property in $properties) +#if ($property.widgetType == "DROPDOWN") + ${dollar}scope.service${property.name} = '${property.widgetDropdownControllerUrl}'; + + const lastSearchValues${property.name} = new Set(); + const allValues${property.name} = []; + let loadMoreOptions${property.name}Counter = 0; + $scope.options${property.name}Loading = false; + $scope.options${property.name}HasMore = true; + + $scope.loadMoreOptions${property.name} = () => { + const limit = 20; + $scope.options${property.name}Loading = true; + ${dollar}http.get(`${property.widgetDropdownControllerUrl}?$limit=${dollar}{limit}&$offset=${dollar}{++loadMoreOptions${property.name}Counter * limit}`) + .then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const resultValues = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + const newValues = []; + resultValues.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + newValues.push(e); + } + }); + newValues.forEach(e => { + if (!${dollar}scope.options${property.name}.find(o => o.value === e.value)) { + ${dollar}scope.options${property.name}.push(e); + } + }) + $scope.options${property.name}HasMore = resultValues.length > 0; + $scope.options${property.name}Loading = false; + }, (error) => { + $scope.options${property.name}Loading = false; + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }; + + $scope.onOptions${property.name}Change = (event) => { + if (allValues${property.name}.length === 0) { + allValues${property.name}.push(...${dollar}scope.options${property.name}); + } + if (event.originalEvent.target.value === '') { + allValues${property.name}.sort((a, b) => a.text.localeCompare(b.text)); + ${dollar}scope.options${property.name} = allValues${property.name}; + $scope.options${property.name}HasMore = true; + } else if (isText(event.which)) { + $scope.options${property.name}HasMore = false; + let cacheHit = false; + Array.from(lastSearchValues${property.name}).forEach(e => { + if (event.originalEvent.target.value.startsWith(e)) { + cacheHit = true; + } + }) + if (!cacheHit) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownValue}', operator: 'LIKE', value: `${dollar}{event.originalEvent.target.value}%` } + ] + }).then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const searchResult = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + searchResult.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + } + }); + ${dollar}scope.options${property.name} = allValues${property.name}.filter(e => e.text.toLowerCase().startsWith(event.originalEvent.target.value.toLowerCase())); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + lastSearchValues${property.name}.add(event.originalEvent.target.value); + } + } + }; + +#end +#end + + function isText(keycode) { + if ((keycode >= 48 && keycode <= 90) || (keycode >= 96 && keycode <= 111) || (keycode >= 186 && keycode <= 222) || [8, 46, 173].includes(keycode)) return true; + return false; + } +#end + +#foreach ($property in $properties) +#if($property.widgetDependsOnProperty) + ${dollar}scope.${dollar}watch('entity.${property.widgetDependsOnProperty}', function (newValue, oldValue) { + if (newValue !== undefined && newValue !== null) { + ${dollar}http.get(${dollar}scope.service${property.widgetDependsOnProperty} + '/' + newValue).then((response) => { + let valueFrom = response.data.${property.widgetDependsOnValueFrom}; +#if($property.widgetType != "DROPDOWN") + $scope.entity.${property.name} = valueFrom; +#end +#if($property.widgetType == "DROPDOWN") + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDependsOnFilterBy}', operator: 'EQ', value: valueFrom } + ] + }).then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + if ($scope.action !== 'select' && newValue !== oldValue) { + if (${dollar}scope.options${property.name}.length == 1) { + $scope.entity.${property.name} = ${dollar}scope.options${property.name}[0].value; + } else { + $scope.entity.${property.name} = undefined; + } + } + }, (error) => { + console.error(error); + }); +#end + }, (error) => { + console.error(error); + }); + } + }); + +#end +#end + $scope.alert = (message) => { + if (message) Dialogs.showAlert({ + title: description, + message: message, + type: AlertTypes.Information, + preformatted: true, + }); + }; + + $scope.cancel = () => { + $scope.entity = {}; + $scope.action = 'select'; + Dialogs.closeWindow({ id: '${name}-details' }); + }; + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/index.html.template new file mode 100644 index 00000000000..222e1978230 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/index.html.template @@ -0,0 +1,578 @@ +#set($dollar = '$') + + + + + + + + + + + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.relationshipType != "COMPOSITION") +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + + More Options + + + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+ #if($property.description) +
+ +
+ #end +
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + +#if(!$property.isCalculatedProperty) + +#end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + +#if(!$property.isCalculatedProperty) + +#end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end +
+ #if($property.description) +
+ +
+ #end +
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/view.extension.template new file mode 100644 index 00000000000..ce739c305e7 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/dialog-window/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/view.js.template new file mode 100644 index 00000000000..83ee2a40aad --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/dialog-window/view.js.template @@ -0,0 +1,17 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-details', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/dialog-window/index.html', + perspectiveName: '#if($hasReferencedProjection)${referencedProjectionPerspectiveName}#else${perspectiveName}#end' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/index.html.template new file mode 100644 index 00000000000..82ead712f55 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/index.html.template @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + {{'$projectName:${tprefix}.messages.detailSelectRecord' | t}} + + + + {{'$projectName:${tprefix}.defaults.items' | t}} + + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.widgetIsMajor) + +#end +#end + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.widgetIsMajor) +#if($property.widgetType == "DROPDOWN") + +#elseif($property.widgetType == "EMAIL") + +#elseif($property.widgetType == "URL") + +#elseif($property.widgetType == "TEL") + +#elseif($property.widgetType == "COLOR") + +#elseif($property.widgetType == "WEEK") + +#elseif($property.widgetType == "MONTH") + +#elseif($property.widgetType == "TIME") + +#elseif($property.widgetType == "DATETIME-LOCAL") + +#elseif($property.widgetType == "DATE") + +#elseif($property.widgetType == "CHECKBOX") + +#else + +#end +#end +#end + + + +
{{ '$projectName:${tprefix}.t.$property.dataName' | t:'$property.name' }}
{{'$projectName:${tprefix}.messages.noData' | t}}
+ {{options${property.name}Value(next.${property.name})}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + + + + + + + + + + + + + + + {{next.${property.name}}} + + + + + + + + + + + + + +
+
+ + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/view.extension.template new file mode 100644 index 00000000000..4f6c51e52dd --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/view.js", + "extensionPoint": "application-views", + "description": "${projectName} - Application View - Details"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/view.js.template new file mode 100644 index 00000000000..30d6da8dc27 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/detail/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + region: 'bottom', + lazyLoad: false, + autoFocusTab: true, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${masterEntity}/${name}/index.html', + perspectiveName: '#if($hasReferencedProjection)${referencedProjectionPerspectiveName}#else${perspectiveName}#end' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/controller.js.template new file mode 100644 index 00000000000..ba2093a6411 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/controller.js.template @@ -0,0 +1,204 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end ViewParameters) => { + const Dialogs = new DialogHub(); + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { +#foreach ($property in $properties) +#if($property.isDateType) + if (params?.entity?.${property.name}From) { + params.entity.${property.name}From = new Date(params.entity.${property.name}From); + } + if (params?.entity?.${property.name}To) { + params.entity.${property.name}To = new Date(params.entity.${property.name}To); + } +#end +#end + $scope.entity = params.entity ?? {}; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } + + $scope.filter = () => { + let entity = $scope.entity; + const filter = { + $filter: { + conditions: [], + sorts: [], + limit: 20, + offset: 0 + } + }; +#foreach ($property in $properties) +#if($property.dataTypeTypescript == 'number') + if (entity.${property.name} !== undefined) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'boolean') + if (entity.${property.name} !== undefined && entity.is${property.name}Indeterminate === false) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'string') + if (entity.${property.name}) { + const condition = { propertyName: '${property.name}', operator: 'LIKE', value: `%$dollar{entity.${property.name}}%` }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'Date') + if (entity.${property.name}From) { + const condition = { propertyName: '${property.name}', operator: 'GE', value: entity.${property.name}From }; + filter.$filter.conditions.push(condition); + } + if (entity.${property.name}To) { + const condition = { propertyName: '${property.name}', operator: 'LE', value: entity.${property.name}To }; + filter.$filter.conditions.push(condition); + } +#end +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', data: { + entity: entity, + filter: filter + }}); + Dialogs.triggerEvent('${projectName}.${perspectiveName}.${name}.clearDetails'); + $scope.cancel(); + }; + + $scope.resetFilter = () => { + $scope.entity = {}; + $scope.filter(); +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + lastSearchValues${property.name}.clear(); + allValues${property.name}.length = 0; +#end +#end +#end + }; + + $scope.cancel = () => { + Dialogs.closeWindow({ id: '${name}-filter' }); + }; + + $scope.clearErrorMessage = () => { + $scope.errorMessage = null; + }; + +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const lastSearchValues${property.name} = new Set(); + const allValues${property.name} = []; + let loadMoreOptions${property.name}Counter = 0; + $scope.options${property.name}Loading = false; + $scope.options${property.name}HasMore = true; + + $scope.loadMoreOptions${property.name} = () => { + const limit = 20; + $scope.options${property.name}Loading = true; + ${dollar}http.get(`${property.widgetDropdownControllerUrl}?$limit=${dollar}{limit}&$offset=${dollar}{++loadMoreOptions${property.name}Counter * limit}`) + .then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const resultValues = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + const newValues = []; + resultValues.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + newValues.push(e); + } + }); + newValues.forEach(e => { + if (!${dollar}scope.options${property.name}.find(o => o.value === e.value)) { + ${dollar}scope.options${property.name}.push(e); + } + }) + $scope.options${property.name}HasMore = resultValues.length > 0; + $scope.options${property.name}Loading = false; + }, (error) => { + $scope.options${property.name}Loading = false; + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }; + + $scope.onOptions${property.name}Change = (event) => { + if (allValues${property.name}.length === 0) { + allValues${property.name}.push(...${dollar}scope.options${property.name}); + } + if (event.originalEvent.target.value === '') { + allValues${property.name}.sort((a, b) => a.text.localeCompare(b.text)); + ${dollar}scope.options${property.name} = allValues${property.name}; + $scope.options${property.name}HasMore = true; + } else if (isText(event.which)) { + $scope.options${property.name}HasMore = false; + let cacheHit = false; + Array.from(lastSearchValues${property.name}).forEach(e => { + if (event.originalEvent.target.value.startsWith(e)) { + cacheHit = true; + } + }) + if (!cacheHit) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownValue}', operator: 'LIKE', value: `${dollar}{event.originalEvent.target.value}%` } + ] + }).then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const searchResult = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + searchResult.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + } + }); + ${dollar}scope.options${property.name} = allValues${property.name}.filter(e => e.text.toLowerCase().startsWith(event.originalEvent.target.value.toLowerCase())); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + lastSearchValues${property.name}.add(event.originalEvent.target.value); + } + } + }; + +#end +#end + function isText(keycode) { + if ((keycode >= 48 && keycode <= 90) || (keycode >= 96 && keycode <= 111) || (keycode >= 186 && keycode <= 222) || [8, 46, 173].includes(keycode)) return true; + return false; + } + +#end +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/index.html.template new file mode 100644 index 00000000000..3c5162eb9c6 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/index.html.template @@ -0,0 +1,336 @@ +#set($dollar = '$') + + + + + + + + + + + + + + + + {{ errorMessage }} + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + + More Options + + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/view.extension.template new file mode 100644 index 00000000000..8b596562b61 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-filter/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/view.js.template new file mode 100644 index 00000000000..3a25b9a3a55 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-filter/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-filter', + label: '${name} Filter', + translation: { + key: '$projectName:${tprefix}.extName', + options: { + content: '$t($projectName:${tprefix}.t.$dataName) $t($projectName:${tprefix}.defaults.filter)', + } + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-filter/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/controller.js.template new file mode 100644 index 00000000000..90dfec0f29a --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/controller.js.template @@ -0,0 +1,289 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', ($scope, ${dollar}http, ViewParameters, LocaleService, EntityService) => { + const Dialogs = new DialogHub(); + const Notifications = new NotificationHub(); + let description = 'Description'; + let propertySuccessfullyCreated = '${name} successfully created'; + let propertySuccessfullyUpdated = '${name} successfully updated'; + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + $scope.formHeaders = { + select: '${name} Details', + create: 'Create ${name}', + update: 'Update ${name}' + }; + $scope.action = 'select'; + + LocaleService.onInit(() => { + description = LocaleService.t('$projectName:${tprefix}.defaults.description'); + $scope.formHeaders.select = LocaleService.t('$projectName:${tprefix}.defaults.formHeadSelect', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + $scope.formHeaders.create = LocaleService.t('$projectName:${tprefix}.defaults.formHeadCreate', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + $scope.formHeaders.update = LocaleService.t('$projectName:${tprefix}.defaults.formHeadUpdate', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + propertySuccessfullyCreated = LocaleService.t('$projectName:${tprefix}.messages.propertySuccessfullyCreated', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + propertySuccessfullyUpdated = LocaleService.t('$projectName:${tprefix}.messages.propertySuccessfullyUpdated', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + }); + + let params = ViewParameters.get(); + if (Object.keys(params).length) { + $scope.action = params.action; +#foreach ($property in $properties) +#if($property.isDateType) + if (params.entity.${property.name}) { + params.entity.${property.name} = new Date(params.entity.${property.name}); + } +#end +#end + $scope.entity = params.entity; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const options${property.name}Map = new Map(); + params.options${property.name}?.forEach(e => options${property.name}Map.set(e.value, e)); + $scope.options${property.name} = Array.from(options${property.name}Map.values()); +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } + + $scope.create = () => { + let entity = $scope.entity; + entity[$scope.selectedMainEntityKey] = $scope.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN" && $property.widgetDropDownMultiSelect) + if (entity.${property.name}) { + entity.${property.name} = entity.${property.name}.join(); + } +#end +#end + EntityService.create(entity).then((response) => { + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entityCreated', data: response.data }); + Notifications.show({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + description: propertySuccessfullyCreated, + type: 'positive' + }); + $scope.cancel(); + }, (error) => { + const message = error.data ? error.data.message : ''; + $scope.$evalAsync(() => { + $scope.errorMessage = LocaleService.t('$projectName:${tprefix}.messages.error.unableToCreate', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }); + }); + console.error('EntityService:', error); + }); + }; + + $scope.update = () => { + let id = ${dollar}scope.entity.${primaryKeysString}; + let entity = $scope.entity; + entity[$scope.selectedMainEntityKey] = $scope.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN" && $property.widgetDropDownMultiSelect) + if (entity.${property.name}) { + entity.${property.name} = entity.${property.name}.join(); + } +#end +#end + EntityService.update(id, entity).then((response) => { + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entityUpdated', data: response.data }); + $scope.cancel(); + Notifications.show({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + description: propertySuccessfullyUpdated, + type: 'positive' + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + $scope.$evalAsync(() => { + $scope.errorMessage = LocaleService.t('$projectName:${tprefix}.messages.error.unableToUpdate', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }); + }); + console.error('EntityService:', error); + }); + }; + +#if($hasDropdowns) +#foreach ($property in $properties) +#if ($property.widgetType == "DROPDOWN") + ${dollar}scope.service${property.name} = '${property.widgetDropdownControllerUrl}'; + + $scope.options${property.name} = []; + + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + + const lastSearchValues${property.name} = new Set(); + const allValues${property.name} = []; + let loadMoreOptions${property.name}Counter = 0; + $scope.options${property.name}Loading = false; + $scope.options${property.name}HasMore = true; + + $scope.loadMoreOptions${property.name} = () => { + const limit = 20; + $scope.options${property.name}Loading = true; + ${dollar}http.get(`${property.widgetDropdownControllerUrl}?$limit=${dollar}{limit}&$offset=${dollar}{++loadMoreOptions${property.name}Counter * limit}`) + .then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const resultValues = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + const newValues = []; + resultValues.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + newValues.push(e); + } + }); + newValues.forEach(e => { + if (!${dollar}scope.options${property.name}.find(o => o.value === e.value)) { + ${dollar}scope.options${property.name}.push(e); + } + }) + $scope.options${property.name}HasMore = resultValues.length > 0; + $scope.options${property.name}Loading = false; + }, (error) => { + $scope.options${property.name}Loading = false; + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }; + + $scope.onOptions${property.name}Change = (event) => { + if (allValues${property.name}.length === 0) { + allValues${property.name}.push(...${dollar}scope.options${property.name}); + } + if (event.originalEvent.target.value === '') { + allValues${property.name}.sort((a, b) => a.text.localeCompare(b.text)); + ${dollar}scope.options${property.name} = allValues${property.name}; + $scope.options${property.name}HasMore = true; + } else if (isText(event.which)) { + $scope.options${property.name}HasMore = false; + let cacheHit = false; + Array.from(lastSearchValues${property.name}).forEach(e => { + if (event.originalEvent.target.value.startsWith(e)) { + cacheHit = true; + } + }) + if (!cacheHit) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownValue}', operator: 'LIKE', value: `${dollar}{event.originalEvent.target.value}%` } + ] + }).then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const searchResult = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + searchResult.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + } + }); + ${dollar}scope.options${property.name} = allValues${property.name}.filter(e => e.text.toLowerCase().startsWith(event.originalEvent.target.value.toLowerCase())); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + lastSearchValues${property.name}.add(event.originalEvent.target.value); + } + } + }; +#end +#end + function isText(keycode) { + if ((keycode >= 48 && keycode <= 90) || (keycode >= 96 && keycode <= 111) || (keycode >= 186 && keycode <= 222) || [8, 46, 173].includes(keycode)) return true; + return false; + } + +#end + +#foreach ($property in $properties) +#if($property.widgetDependsOnProperty) + ${dollar}scope.${dollar}watch('entity.${property.widgetDependsOnProperty}', (newValue, oldValue) => { + if (newValue !== undefined && newValue !== null) { + ${dollar}http.get(${dollar}scope.service${property.widgetDependsOnProperty} + '/' + newValue).then((response) => { + let valueFrom = response.data.${property.widgetDependsOnValueFrom}; +#if($property.widgetType != "DROPDOWN") + $scope.entity.${property.name} = valueFrom; +#end +#if($property.widgetType == "DROPDOWN") + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDependsOnFilterBy}', operator: 'EQ', value: valueFrom } + ] + }).then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + if ($scope.action !== 'select' && newValue !== oldValue) { + if (${dollar}scope.options${property.name}.length == 1) { + $scope.entity.${property.name} = ${dollar}scope.options${property.name}[0].value; + } else { + $scope.entity.${property.name} = undefined; + } + } + }, (error) => { + console.error(error); + }); +#end + }, (error) => { + console.error(error); + }); + } + }); + +#end +#end + $scope.alert = (message) => { + if (message) Dialogs.showAlert({ + title: description, + message: message, + type: AlertTypes.Information, + preformatted: true, + }); + }; + + $scope.cancel = () => { + $scope.entity = {}; + $scope.action = 'select'; + Dialogs.closeWindow({ id: '${name}-details' }); + }; + + $scope.clearErrorMessage = () => { + $scope.errorMessage = null; + }; + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/index.html.template new file mode 100644 index 00000000000..9508241f605 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/index.html.template @@ -0,0 +1,580 @@ +#set($dollar = '$') + + + + + + + + + + + + + + + + + {{ errorMessage }} + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + + More Options + + + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+ #if($property.description) +
+ +
+ #end +
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end +
+ #if($property.description) +
+ +
+ #end +
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/view.extension.template new file mode 100644 index 00000000000..e0467a1d892 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-window/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/view.js.template new file mode 100644 index 00000000000..7d7d5180fb3 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/dialog-window/view.js.template @@ -0,0 +1,27 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: "${name}-details", + label: "${name}", + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + path: "/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/dialog-window/index.html", + perspectiveName: "${perspectiveName}", +#if($perspectiveRole || $roleRead) + roles: [ +#if($perspectiveRole) + "${perspectiveRole}", +#end +#if($roleRead) + "${roleRead}", +#end + ] +#end +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/index.html.template new file mode 100644 index 00000000000..4424b86fdd4 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/index.html.template @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + {{'$projectName:${tprefix}.defaults.items' | t}} + + + + + + + + + + + + + + + + + + + + + +#elseif($masterProperties.title.widgetType == "DATE") + item-title="{{next.${masterProperties.title.name} | date: 'dd/MMM/yyyy'}}"> +#elseif($masterProperties.title.widgetType == "DATETIME-LOCAL") + item-title="{{next.${masterProperties.title.name} | date: 'dd/MMM/yyyy HH:MM'}}"> +#elseif($masterProperties.title.widgetType == "TIME") + item-title="{{next.${masterProperties.title.name} | date: 'HH:MM:ss'}}"> +#elseif($masterProperties.title.widgetType == "WEEK") + item-title="Week {{next.${masterProperties.title.name} | date: 'ww'}}"> +#else + item-title="{{next.${masterProperties.title.name}}}"> +#end + +#foreach ($property in $masterProperties.properties) +#if($property.widgetType == "DROPDOWN") + {{options${property.name}Value(next.${property.name})}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "DATE") + {{next.${property.name} | date: "dd/MMM/yyyy"}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "DATETIME-LOCAL") + {{next.${property.name} | date: "dd/MMM/yyyy HH:MM"}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "TIME") + {{next.${property.name} | date: "HH:MM:ss"}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "WEEK") + Week {{next.${property.name} | date: "ww"}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "EMAIL") + {{next.${property.name}}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "URL") + {{next.${property.name}}}#if(!$foreach.isLast()) |#end +#elseif($property.widgetType == "TEL") + {{next.${property.name}}}#if(!$foreach.isLast()) |#end +#else + {{next.${property.name}}}#if(!$foreach.isLast()) |#end +#end +#end + + + + + + + {{ '$projectName:${tprefix}.defaults.loadMore' | t }} + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/controller.js.template new file mode 100644 index 00000000000..929a0778448 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/controller.js.template @@ -0,0 +1,363 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(["EntityServiceProvider", (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', ($scope, ${dollar}http, Extensions, LocaleService, EntityService) => { + const Dialogs = new DialogHub(); + const Notifications = new NotificationHub(); + let description = 'Description'; + let propertySuccessfullyCreated = '${name} successfully created'; + let propertySuccessfullyUpdated = '${name} successfully updated'; + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + $scope.formHeaders = { + select: '${name} Details', + create: 'Create ${name}', + update: 'Update ${name}' + }; + $scope.action = 'select'; + + LocaleService.onInit(() => { + description = LocaleService.t('$projectName:${tprefix}.defaults.description'); + $scope.formHeaders.select = LocaleService.t('$projectName:${tprefix}.defaults.formHeadSelect', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + $scope.formHeaders.create = LocaleService.t('$projectName:${tprefix}.defaults.formHeadCreate', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + $scope.formHeaders.update = LocaleService.t('$projectName:${tprefix}.defaults.formHeadUpdate', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + propertySuccessfullyCreated = LocaleService.t('$projectName:${tprefix}.messages.propertySuccessfullyCreated', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + propertySuccessfullyUpdated = LocaleService.t('$projectName:${tprefix}.messages.propertySuccessfullyUpdated', { name: '$t($projectName:${tprefix}.t.${dataName})' }); + }); + + //-----------------Custom Actions-------------------// + Extensions.getWindows(['${projectName}-custom-action']).then((response) => { + $scope.entityActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && e.type === 'entity'); + }); + + $scope.triggerEntityAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + params: { + id: $scope.entity.${primaryKeysString} + }, + closeButton: true + }); + }; + //-----------------Custom Actions-------------------// + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.clearDetails', handler: () => { + $scope.$evalAsync(() => { + $scope.entity = {}; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end + $scope.action = 'select'; + }); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entitySelected', handler: (data) => { + $scope.$evalAsync(() => { + #foreach ($property in $properties) +#if($property.isDateType) + if (data.entity.${property.name}) { + data.entity.${property.name} = new Date(data.entity.${property.name}); + } +#end +#end + $scope.entity = data.entity; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = data.options${property.name}; +#end +#end + $scope.action = 'select'; + }); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.createEntity', handler: (data) => { + $scope.$evalAsync(() => { + $scope.entity = {}; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = data.options${property.name}; +#end +#end + $scope.action = 'create'; + }); + }}); + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.updateEntity', handler: (data) => { + $scope.$evalAsync(() => { +#foreach ($property in $properties) +#if($property.isDateType) + if (data.entity.${property.name}) { + data.entity.${property.name} = new Date(data.entity.${property.name}); + } +#end +#end + $scope.entity = data.entity; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = data.options${property.name}; +#end +#end + $scope.action = 'update'; + }); + }}); + +#foreach ($property in $properties) +#if ($property.widgetType == "DROPDOWN") + ${dollar}scope.service${property.name} = '${property.widgetDropdownControllerUrl}'; +#end +#end + +#foreach ($property in $properties) +#if($property.widgetDependsOnProperty) + + ${dollar}scope.${dollar}watch('entity.${property.widgetDependsOnProperty}', (newValue, oldValue) => { + if (newValue !== undefined && newValue !== null) { + ${dollar}http.get(${dollar}scope.service${property.widgetDependsOnProperty} + '/' + newValue).then((response) => { + let valueFrom = response.data.${property.widgetDependsOnValueFrom}; +#if($property.widgetType != "DROPDOWN") + $scope.entity.${property.name} = valueFrom; +#end +#if($property.widgetType == "DROPDOWN") + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDependsOnFilterBy}', operator: 'EQ', value: valueFrom } + ] + }).then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + if ($scope.action !== 'select' && newValue !== oldValue) { + if (${dollar}scope.options${property.name}.length == 1) { + $scope.entity.${property.name} = ${dollar}scope.options${property.name}[0].value; + } else { + $scope.entity.${property.name} = undefined; + } + } + }, (error) => { + console.error(error); + }); +#end + }, (error) => { + console.error(error); + }); + } + }); +#end +#end + //-----------------Events-------------------// + + $scope.create = () => { +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN" && $property.widgetDropDownMultiSelect) + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.join(); +#end +#end + EntityService.create($scope.entity).then((response) => { + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entityCreated', data: response.data }); + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.clearDetails' , data: response.data }); + Notifications.show({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + description: propertySuccessfullyCreated, + type: 'positive' + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCreate', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + + $scope.update = () => { +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN" && $property.widgetDropDownMultiSelect) + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.join(); +#end +#end + EntityService.update($scope.entity.${primaryKeysString}, $scope.entity).then((response) => { + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entityUpdated', data: response.data }); + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.clearDetails', data: response.data }); + Notifications.show({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + description: propertySuccessfullyUpdated, + type: 'positive' + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCreate', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + + $scope.cancel = () => { + Dialogs.triggerEvent('${projectName}.${perspectiveName}.${name}.clearDetails'); + }; + + //-----------------Dialogs-------------------// + $scope.alert = (message) => { + if (message) Dialogs.showAlert({ + title: description, + message: message, + type: AlertTypes.Information, + preformatted: true, + }); + }; + +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.create${property.name} = () => { + Dialogs.showWindow({ + id: '${property.relationshipEntityName}-details', + params: { + action: 'create', + entity: {}, + }, + closeButton: false + }); + }; +#end +#end +#end + + //-----------------Dialogs-------------------// + + + + //----------------Dropdowns-----------------// + +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + const lastSearchValues${property.name} = new Set(); + const allValues${property.name} = []; + let loadMoreOptions${property.name}Counter = 0; + $scope.options${property.name}Loading = false; + $scope.options${property.name}HasMore = true; + + $scope.loadMoreOptions${property.name} = () => { + const limit = 20; + $scope.options${property.name}Loading = true; + ${dollar}http.get(`${property.widgetDropdownControllerUrl}?$limit=${dollar}{limit}&$offset=${dollar}{++loadMoreOptions${property.name}Counter * limit}`) + .then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const resultValues = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + const newValues = []; + resultValues.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + newValues.push(e); + } + }); + newValues.forEach(e => { + if (!${dollar}scope.options${property.name}.find(o => o.value === e.value)) { + ${dollar}scope.options${property.name}.push(e); + } + }) + $scope.options${property.name}HasMore = resultValues.length > 0; + $scope.options${property.name}Loading = false; + }, (error) => { + $scope.options${property.name}Loading = false; + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }; + + $scope.onOptions${property.name}Change = (event) => { + if (allValues${property.name}.length === 0) { + allValues${property.name}.push(...${dollar}scope.options${property.name}); + } + if (event.originalEvent.target.value === '') { + allValues${property.name}.sort((a, b) => a.text.localeCompare(b.text)); + ${dollar}scope.options${property.name} = allValues${property.name}; + $scope.options${property.name}HasMore = true; + } else if (isText(event.which)) { + $scope.options${property.name}HasMore = false; + let cacheHit = false; + Array.from(lastSearchValues${property.name}).forEach(e => { + if (event.originalEvent.target.value.startsWith(e)) { + cacheHit = true; + } + }) + if (!cacheHit) { + ${dollar}http.post('${property.widgetDropdownControllerUrl}/search', { + conditions: [ + { propertyName: '${property.widgetDropDownValue}', operator: 'LIKE', value: `${dollar}{event.originalEvent.target.value}%` } + ] + }).then((response) => { + const optionValues = allValues${property.name}.map(e => e.value); + const searchResult = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + searchResult.forEach(e => { + if (!optionValues.includes(e.value)) { + allValues${property.name}.push(e); + } + }); + ${dollar}scope.options${property.name} = allValues${property.name}.filter(e => e.text.toLowerCase().startsWith(event.originalEvent.target.value.toLowerCase())); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + lastSearchValues${property.name}.add(event.originalEvent.target.value); + } + } + }; + + $scope.refresh${property.name} = () => { + $scope.options${property.name} = []; + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + allValues${property.name}.length === 0; + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); + }; +#end +#end + + function isText(keycode) { + if ((keycode >= 48 && keycode <= 90) || (keycode >= 96 && keycode <= 111) || (keycode >= 186 && keycode <= 222) || [8, 46, 173].includes(keycode)) return true; + return false; + } +#end + + //----------------Dropdowns-----------------// + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/index.html.template new file mode 100644 index 00000000000..42882bd555d --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/index.html.template @@ -0,0 +1,589 @@ +#set($dollar = '$') + + + + + + + + + + + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + + More Options + + +
+
+ + + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+ #if($property.description) +
+ +
+ #end +
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end +
+ #if($property.description) +
+ +
+ #end +
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ #if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end + #end + + + #if(!$property.isCalculatedProperty) + + #end + #if($property.description) + + #end +
+
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/view.extension.template new file mode 100644 index 00000000000..2eaa6ee3f86 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/main-details/view.js", + "extensionPoint": "application-views", + "description": "${projectName} - Application View - Main Details"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/view.js.template new file mode 100644 index 00000000000..87de655838a --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/main-details/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-details', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + region: 'center', + lazyLoad: false, + autoFocusTab: true, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/main-details/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/view.extension.template new file mode 100644 index 00000000000..f9ae92d4291 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/view.js", + "extensionPoint": "application-views", + "description": "${projectName} - Application View"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/view.js.template new file mode 100644 index 00000000000..a3927b88432 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/master-manage/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + region: 'left', + lazyLoad: false, + autoFocusTab: false, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/${name}/index.html', + perspectiveName: '${perspectiveName}' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/perspective.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/perspective.extension.template new file mode 100644 index 00000000000..bb5708b3b2e --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/perspective.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/${perspectiveName}/perspective.js", + "extensionPoint": "application-perspectives", + "description": "${projectName} - Perspective - ${perspectiveName}"#if($perspectiveRole || $roleRead || $roleWrite), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead},#end#if($roleWrite)${roleWrite}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/perspective.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/perspective.js.template new file mode 100644 index 00000000000..9c57d2021f1 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/perspective.js.template @@ -0,0 +1,29 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const perspectiveData = { + id: '${perspectiveName}', + label: '${perspectiveLabel}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, +#if($perspectiveHeader) + header: '${perspectiveHeader}', + headerTranslation: { + key: '$projectName:${tprefix}.t.${perspectiveName}pheader', + }, +#end + path: '/services/web/${projectName}/gen/${genFolderName}/ui/${perspectiveName}/index.html', +#if($perspectiveNavId) + groupId: '${perspectiveNavId}', +#end +#if($perspectiveOrder) + order: ${perspectiveOrder}, +#end + icon: '${perspectiveIcon}' +}; +if (typeof exports !== 'undefined') { + exports.getPerspective = () => perspectiveData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/controller.js.template new file mode 100644 index 00000000000..0c7647c1517 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/controller.js.template @@ -0,0 +1,218 @@ +#set($dollar = '$') +#set($hasDropdowns = false) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") +#set($hasDropdowns = true) +#end +#end +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") +#set($hasDropdowns = true) +#end +#end +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end EntityService, LocaleService) => { + const Dialogs = new DialogHub(); + $scope.filter = {}; + + const ctx = document.getElementById('myChart'); + const myChart = new Chart(ctx, { +#if($layoutType == "REPORT_BAR") + type: 'bar', +#elseif($layoutType == "REPORT_LINE") + type: 'line', +#elseif($layoutType == "REPORT_PIE") + type: 'pie', +#elseif($layoutType == "REPORT_DOUGHNUT") + type: 'doughnut', +#elseif($layoutType == "REPORT_POLARAREA") + type: 'polarArea', +#elseif($layoutType == "REPORT_RADAR") + type: 'radar', +#end + data: { + labels: [], + datasets: [] + } + }); + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.filter', handler: (data) => { + $scope.filter = data; + ${dollar}scope.loadPage(); + }}); + //-----------------Events-------------------// + + $scope.loadPage = () => { + EntityService.count($scope.filter).then((resp) => { + $scope.dataCount = resp.data.count; + EntityService.list($scope.filter).then((response) => { +#if($hasDates) + response.data.forEach(e => { +#foreach ($property in $properties) +#if($property.isDateType) + if (e.${property.name}) { + e.${property.name} = new Date(e.${property.name}); + } +#end +#end + }); + +#end + $scope.data = response.data; + myChart.data.labels = ${dollar}scope.data.map(e => #foreach($property in $properties)#if($property.dataPrimaryKey)e.${property.name}#end#end); + myChart.data.datasets = [ +#foreach ($property in $properties) +#if(!$property.dataPrimaryKey) + { +#if($property.widgetLabel) + label: LocaleService.t('$projectName:${tprefix}.t.$property.dataName', '${property.widgetLabel}'), +#else + label: '${property.name}', +#end + data: ${dollar}scope.data.map(e => e.${property.name}), +#if($layoutType == "REPORT_LINE") + fill: true, +#end + borderWidth: 1 + }, +#end +#end + ]; + myChart.canvas.parentNode.style.height = '90%'; + myChart.update(); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCount', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + $scope.loadPage(); + + $scope.openFilter = () => { + Dialogs.showWindow({ + id: '${name}-details-filter', + params: { + action: 'filter', + filter: $scope.filter, +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end + }, + }); + }; + +#if($hasDropdowns) + //----------------Dropdowns-----------------// +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); +#end +#end +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") + + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); +#end +#end +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = (optionKey) => { +#if($property.widgetDropDownMultiSelect) + const values = []; + if (Array.isArray(optionKey)) { + optionKey = optionKey.join(); + } + optionKey.split(',').map(e => parseInt(e)).forEach(key => { + const found = ${dollar}scope.options${property.name}.find(e => e.value === key); + if (found) { + values.push(found.text); + } + }); + return values.join(', '); +#else + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; +#end + }; +#end +#end +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = (optionKey) => { + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; + }; +#end +#end + //----------------Dropdowns-----------------// +#end + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/controller.js.template new file mode 100644 index 00000000000..f87c039d48e --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/controller.js.template @@ -0,0 +1,51 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, ViewParameters) => { + const Dialogs = new DialogHub(); + $scope.forms = { + details: {}, + }; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { +#foreach ($property in $filter.properties) +#if($property.isDateType) + if (params?.filter?.${property.name}) { + params.filter.${property.name} = new Date(params.filter.${property.name}); + } +#end +#end + $scope.entity = params.filter ?? {}; +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = params.options${property.name}; +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } + + $scope.filter = () => { + const filter = { + ...$scope.entity + }; +#foreach ($property in $filter.properties) +#if($property.isDateType) + filter.${property.name} = filter.${property.name}?.getTime(); +#end +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.filter', data: filter }); + $scope.cancel(); + }; + + $scope.resetFilter = () => { + $scope.entity = {}; + $scope.filter(); + }; + + $scope.cancel = () => { + Dialogs.closeWindow({ id: '${name}-details-filter' }); + }; +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/index.html.template new file mode 100644 index 00000000000..f993cbea70c --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/index.html.template @@ -0,0 +1,462 @@ + + + + + + + + + + + + + + + + + +#foreach ($property in $filter.properties) +#if(!$property.dataAutoIncrement && !$property.dataPrimaryKey) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+ + +
+#elseif($property.widgetType == "CHECKBOX") + +
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+ + +
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/view.extension.template new file mode 100644 index 00000000000..4df3b883da0 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-window-filter/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window Filter"#if($perspectiveRole || $roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/view.js.template new file mode 100644 index 00000000000..11cf1467699 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/dialog-window-filter/view.js.template @@ -0,0 +1,17 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-details-filter', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-window-filter/index.html', + perspectiveName: 'Reports' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/index.html.template new file mode 100644 index 00000000000..e0ec4e8ae48 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/index.html.template @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + {{'$projectName:${tprefix}.defaults.items' | t}} + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/view.extension.template new file mode 100644 index 00000000000..131c0d28481 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/view.js", + "extensionPoint": "application-reports", + "description": "${projectName} - Application View"#if($perspectiveRole || $roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/view.js.template new file mode 100644 index 00000000000..35a6d21a2e2 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-chart/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + region: 'center', + lazyLoad: true, + autoFocusTab: false, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/Reports/${name}/index.html', + perspectiveName: 'Reports' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/controller.js.template new file mode 100644 index 00000000000..dc97e5f71f6 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/controller.js.template @@ -0,0 +1,137 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', (${dollar}scope, EntityService, LocaleService, Extensions) => { + const Dialogs = new DialogHub(); + const exportsHub = new ExportsHub(); + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 20; + + $scope.triggerExportAction = () => { + let request = EntityService.exportCsv(); + request.then(() => { + exportsHub.refresh(); + }); + } + + //-----------------Custom Actions-------------------// + Extensions.getWindows(['${projectName}-custom-action']).then((response) => { + $scope.pageActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && (e.type === 'page' || e.type === undefined)); + $scope.entityActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && e.type === 'entity'); + }); + + $scope.triggerPageAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + params: { + filterEntity: $scope.filterEntity, + }, + maxWidth: action.maxWidth, + maxHeight: action.maxHeight, + closeButton: true + }); + }; + //-----------------Custom Actions-------------------// + + function resetPagination() { + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 20; + } + resetPagination(); + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', handler: (data) => { + resetPagination(); + $scope.filter = data.filter; + $scope.filterEntity = data.entity; + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + //-----------------Events-------------------// + + $scope.loadPage = (pageNumber, filter) => { + if (!filter && $scope.filter) { + filter = $scope.filter; + } + $scope.dataPage = pageNumber; + EntityService.count(filter).then((resp) => { + if (resp.data) { + $scope.dataCount = resp.data.count; + } + let offset = (pageNumber - 1) * $scope.dataLimit; + let limit = $scope.dataLimit; + let request; + if (filter) { + if (!filter.$filter) { + filter.$filter = {}; + } + filter.$filter.offset = offset; + filter.$filter.limit = limit; + request = EntityService.search(filter); + } else { + request = EntityService.list(offset, limit); + } + request.then((response) => { +#if($hasDates) + response.data.forEach(e => { +#foreach ($property in $properties) +#if($property.isDateType) + if (e.${property.name}) { + e.${property.name} = new Date(e.${property.name}); + } +#end +#end + }); + +#end + $scope.data = response.data; + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${tId}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${tId})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${tId}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCount', { name: '$t($projectName:${tprefix}.t.${tId})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + $scope.loadPage($scope.dataPage, $scope.filter); + + $scope.selectEntity = (entity) => { + $scope.selectedEntity = entity; + }; + + $scope.openDetails = (entity) => { + $scope.selectedEntity = entity; + Dialogs.showWindow({ + id: '${name}-Report-details', + params: { + action: 'select', + entity: entity, + }, + }); + }; + + $scope.openFilter = () => { + Dialogs.showWindow({ + id: '${name}-Report-filter', + params: { + entity: $scope.filterEntity, + }, + }); + }; + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/controller.js.template new file mode 100644 index 00000000000..94413cef269 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/controller.js.template @@ -0,0 +1,56 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, ViewParameters) => { + const Dialogs = new DialogHub(); + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { +#foreach ($parameter in $parameters) +#if($parameter.typeTypescript == 'Date') + if (params?.entity?.${parameter.name}) { + params.entity.${parameter.name} = new Date(params.entity.${parameter.name}); + } +#end +#end + $scope.entity = params.entity ?? {}; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; + } + + $scope.filter = () => { + let entity = $scope.entity; + const filter = { + + }; +#foreach($parameter in $parameters) + if (entity.${parameter.name}) { +#if($parameter.typeTypescript == 'Date') + filter.${parameter.name} = entity.${parameter.name}?.getTime(); +#else + filter.${parameter.name} = entity.${parameter.name}; +#end + } +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', data: { + entity: entity, + filter: filter + } }); + $scope.cancel(); + }; + + $scope.resetFilter = () => { + $scope.entity = {}; + $scope.filter(); + }; + + $scope.cancel = () => { + Dialogs.closeWindow({ id: '${name}-Report-filter' }); + }; + + $scope.clearErrorMessage = () => { + $scope.errorMessage = null; + }; +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/index.html.template new file mode 100644 index 00000000000..3e64acd2057 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/index.html.template @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + +#foreach ($parameter in $parameters) +#if($parameter.typeTypescript == 'boolean') + +
+
+ + ${parameter.name} +
+
+#elseif($parameter.typeTypescript == 'number') + +
+ ${parameter.name} +
+
+ + +
+
+#elseif($parameter.typeJava == 'time') + +
+ ${parameter.name} +
+
+ + + + +
+
+#elseif($parameter.typeJava == 'timestamp') + +
+ ${parameter.name} +
+
+ + + + +
+
+#elseif($parameter.typeJava == 'date') + +
+ ${parameter.name} +
+
+ + + + +
+
+#else + +
+ ${parameter.name} +
+
+ + + + +
+
+#end +#end +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/view.extension.template new file mode 100644 index 00000000000..a680c80d3f2 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-filter/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $security.roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($security.roleRead)${security.roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/view.js.template new file mode 100644 index 00000000000..b62f9628c70 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-filter/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: "${name}-Report-filter", + label: "${label} Report Filter", + translation: { + key: '$projectName:${tprefix}.extName', + options: { + content: '$t($projectName:${tprefix}.t.${tId}) $t($projectName:${tprefix}.defaults.reportFilter)', + } + }, + path: "/services/web/${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-filter/index.html", + perspectiveName: "Reports" +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/controller.js.template new file mode 100644 index 00000000000..9068fb51e80 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/controller.js.template @@ -0,0 +1,66 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', ($scope, EntityService, LocaleService, ViewParameters) => { + const Dialogs = new DialogHub(); + let params = ViewParameters.get(); + if (Object.keys(params).length) { + const filterEntity = params.filterEntity ?? {}; + + $scope.filter = {}; +#foreach ($parameter in $parameters) + if (filterEntity.${parameter.name}) { +#if($parameter.typeTypescript == 'Date') + $scope.filter.${parameter.name} = new Date(filterEntity.${parameter.name}); +#else + $scope.filter.${parameter.name} = filterEntity.${parameter.name}; +#end + } +#end + } + + $scope.loadPage = (filter) => { + if (!filter && $scope.filter) { + filter = $scope.filter; + } + let request; + if (filter) { + request = EntityService.search(filter); + } else { + request = EntityService.list(); + } + request.then((response) => { +#if($hasDates) + response.data.forEach(e => { +#foreach ($column in $columns) +#if($column.typeTypescript == 'Date') + if (e['${column.alias}']) { + e['${column.alias}'] = new Date(e['${column.alias}']); + } +#end +#end + }); + +#end + $scope.data = response.data; + setTimeout(() => { + window.print(); + }, 250); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${tId}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${tId})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + $scope.loadPage($scope.filter); + + window.onafterprint = () => { + Dialogs.closeWindow({ path: viewData.path }); + } + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/index.html.template new file mode 100644 index 00000000000..ae8c5f71c2e --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/index.html.template @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + {{ '$projectName:${tprefix}.defaults.reportTitle' | t:{'name':'$t($projectName:${tprefix}.t.${tId})'}:'${label}' }} + + + + + + #foreach ($column in $columns) + + #end + + + + + + + + #foreach ($column in $columns) + #if($column.typeJava == 'time') + + #elseif($column.typeJava == 'timestamp') + + #elseif($column.typeJava == 'date') + + #elseif($column.typeTypescript == 'boolean') + + #else + + #end + #end + + +
{{ '$projectName:${tprefix}.t.${column.tId}' | t:'${column.label}' }}
{{'$projectName:${tprefix}.messages.noData' | t}}
+ + + + + + + + + {{next['${column.alias}']}}
+
+ + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/print.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/print.extension.template new file mode 100644 index 00000000000..4d88b62f526 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/print.extension.template @@ -0,0 +1,6 @@ +{ + "extensionPoint": "${projectName}-custom-action", + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-print/print.js", + "description": "Print ${name} Report"#if($perspectiveRole || $security.roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($security.roleRead)${security.roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/print.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/print.js.template new file mode 100644 index 00000000000..e72ea300abb --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-print/print.js.template @@ -0,0 +1,15 @@ +const viewData = { + id: '{{projectName}}-Reports-{{name}}-print', + label: 'Print', + translation: { + key: '{{projectName}}:{{tprefix}}.defaults.print', + }, + path: '/services/web/{{projectName}}/gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-print/index.html', + perspective: 'Reports', + view: '{{name}}', + type: 'page', + order: 10 +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/controller.js.template new file mode 100644 index 00000000000..361d77acde4 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/controller.js.template @@ -0,0 +1,18 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, ViewParameters) => { + $scope.entity = {}; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { + $scope.action = 'select'; + +#foreach ($column in $columns) +#if($column.typeTypescript == 'Date') + if (params.entity['${column.alias}']) { + params.entity['${column.alias}'] = new Date(params.entity['${column.alias}']); + } +#end +#end + $scope.entity = params.entity; + } +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/index.html.template new file mode 100644 index 00000000000..5c32bc693c0 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/index.html.template @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + +#foreach ($column in $columns) +#if($column.typeTypescript == 'boolean') + +
+
+ + {{ '$projectName:${tprefix}.t.${column.tId}' | t:'${column.label}' }} +
+
+#elseif($column.typeTypescript == 'number') + +
+ {{ '$projectName:${tprefix}.t.${column.tId}' | t:'${column.label}' }} +
+
+ + +
+
+#elseif($column.typeJava == 'time') + +
+ {{ '$projectName:${tprefix}.t.${column.tId}' | t:'${column.label}' }} +
+
+ + +
+
+#elseif($column.typeJava == 'timestamp') + +
+ {{ '$projectName:${tprefix}.t.${column.tId}' | t:'${column.label}' }} +
+
+ + +
+
+#elseif($column.typeJava == 'date') + +
+ {{ '$projectName:${tprefix}.t.${column.tId}' | t:'${column.label}' }} +
+
+ + +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.${column.tId}' | t:'${column.label}' }} +
+
+ + +
+
+#end +#end +
+
+
+ + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/view.extension.template new file mode 100644 index 00000000000..a21603202c6 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-window/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $security.roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($security.roleRead)${security.roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/view.js.template new file mode 100644 index 00000000000..9745e969ea9 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/dialog-window/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-Report-details', + label: '${label} Report', + translation: { + key: '$projectName:${tprefix}.defaults.reportTitle', + options: { + name: '$t($projectName:${tprefix}.t.${tId})', + } + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-window/index.html', + perspectiveName: 'Reports' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/index.html.template new file mode 100644 index 00000000000..c7fa8570c34 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/index.html.template @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + {{'$projectName:${tprefix}.defaults.items' | t}} +#if($parameters && $parameters.size() > 0) + +#end + + + + + + + + + +#foreach ($column in $columns) + +#end + + + + + + + + +#foreach ($column in $columns) + +#end + + + +
{{ '$projectName:${tprefix}.t.${column.tId}' | t:'${column.label}' }}
{{'$projectName:${tprefix}.messages.noData' | t}}
{{next['${column.alias}']}} + + + + + + + + + + + +
+
+ + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/view.extension.template new file mode 100644 index 00000000000..822b23ace4f --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/view.js", + "extensionPoint": "application-reports", + "description": "${projectName} - Application View"#if($perspectiveRole || $security.roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($security.roleRead)${security.roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/view.js.template new file mode 100644 index 00000000000..d35b195e57f --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-file/view.js.template @@ -0,0 +1,23 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}Report', + label: '${label} Report', + translation: { + key: '$projectName:${tprefix}.defaults.reportTitle', + options: { + name: '$t($projectName:${tprefix}.t.${tId})', + } + }, + region: 'center', + lazyLoad: true, + autoFocusTab: false, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/Reports/${name}/index.html', + perspectiveName: 'Reports' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/controller.js.template new file mode 100644 index 00000000000..d2bd85da9b3 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/controller.js.template @@ -0,0 +1,224 @@ +#set($dollar = '$') +#set($hasDropdowns = false) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") +#set($hasDropdowns = true) +#end +#end +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") +#set($hasDropdowns = true) +#end +#end +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end, EntityService, LocaleService) => { + const Dialogs = new DialogHub(); + + $scope.filter = {}; + + function resetPagination() { + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 20; + } + resetPagination(); + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.filter', handler: (data) => { + $scope.filter = data; + ${dollar}scope.loadPage(1); + }}); + //-----------------Events-------------------// + + $scope.loadPage = (pageNumber) => { + const listFilter = { + $filter: { + offset: (pageNumber - 1) * $scope.dataLimit, + limit: $scope.dataLimit, + ...$scope.filter + } + }; + $scope.dataPage = pageNumber; + EntityService.count($scope.filter).then((resp) => { + $scope.dataCount = resp.data.count; + EntityService.list(listFilter).then((response) => { +#if($hasDates) + response.data.forEach(e => { +#foreach ($property in $properties) +#if($property.isDateType) + if (e.${property.name}) { + e.${property.name} = new Date(e.${property.name}); + } +#end +#end + }); + +#end + $scope.data = response.data; + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), type: AlertTypes.Error }); + console.error('EntityService:', error); + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlertError({ title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCount', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), type: AlertTypes.Error }); + console.error('EntityService:', error); + }); + }; + $scope.loadPage($scope.dataPage); + + $scope.selectEntity = (entity) => { + $scope.selectedEntity = entity; + }; + + $scope.openDetails = (entity) => { + $scope.selectedEntity = entity; + Dialogs.showWindow({ + id: '${name}-details', + params: { + action: 'select', + entity: entity, +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end + }, + }); + }; + + $scope.openFilter = () => { + Dialogs.showWindow({ + id: '${name}-details-filter', + params: { + action: 'filter', + filter: $scope.filter, +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end + } + }); + }; + +#if($hasDropdowns) + + //----------------Dropdowns-----------------// +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); +#end +#end +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); +#end +#end +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") + + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); +#end +#end +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = (optionKey) => { +#if($property.widgetDropDownMultiSelect) + const values = []; + if (Array.isArray(optionKey)) { + optionKey = optionKey.join(); + } + optionKey.split(',').map(e => parseInt(e)).forEach(key => { + const found = ${dollar}scope.options${property.name}.find(e => e.value === key); + if (found) { + values.push(found.text); + } + }); + return values.join(', '); +#else + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; +#end + }; +#end +#end +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = (optionKey) => { + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; + }; +#end +#end + //----------------Dropdowns-----------------// +#end + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/controller.js.template new file mode 100644 index 00000000000..6727ddc7c70 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/controller.js.template @@ -0,0 +1,62 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, ViewParameters) => { + const Dialogs = new DialogHub(); + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { +#foreach ($property in $filter.properties) +#if($property.isDateType) + if (params?.filter?.${property.name}) { + params.filter.${property.name} = new Date(params.filter.${property.name}); + } +#end +#end + $scope.entity = params.filter ?? {}; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = params.options${property.name}; +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end +#foreach ($property in $filter.properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = params.options${property.name}; +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } + + $scope.filter = () => { + const filter = { + ...$scope.entity + }; +#foreach ($property in $filter.properties) +#if($property.isDateType) + filter.${property.name} = filter.${property.name}?.getTime(); +#end +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.filter', data: filter }); + $scope.cancel(); + }; + + $scope.resetFilter = () => { + $scope.entity = {}; + $scope.filter(); + }; + + $scope.cancel = () => { + Dialogs.closeWindow({ id: '${name}-details-filter' }); + }; +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/index.html.template new file mode 100644 index 00000000000..999957e6fd7 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/index.html.template @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + + + + +#foreach ($property in $filter.properties) +#if(!$property.dataAutoIncrement && !$property.dataPrimaryKey) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+ + +
+#elseif($property.widgetType == "CHECKBOX") + +
+ + + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+ + +
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+#if(!$property.isCalculatedProperty) + + #elseif($property.maxLength && $property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMinMax' | t:{'min':'${property.minLength}','max':'${property.maxLength}'} }}"> + #elseif($property.maxLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMax' | t:{'max':'${property.maxLength}'} }}"> + #elseif($property.minLength) + text="{{ '$projectName:${tprefix}.messages.error.lengthMin' | t:{'min':'${property.minLength}'} }}"> + #else + text="{{ '$projectName:${tprefix}.messages.error.incorrectInput' | t }}"> + #end +#end + + +#if(!$property.isCalculatedProperty) + +#end +
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/view.extension.template new file mode 100644 index 00000000000..4df3b883da0 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-window-filter/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window Filter"#if($perspectiveRole || $roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/view.js.template new file mode 100644 index 00000000000..11cf1467699 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window-filter/view.js.template @@ -0,0 +1,17 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-details-filter', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-window-filter/index.html', + perspectiveName: 'Reports' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/controller.js.template new file mode 100644 index 00000000000..3f33cda3422 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/controller.js.template @@ -0,0 +1,28 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, ViewParameters) => { + $scope.entity = {}; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { + $scope.action = 'select'; + +#foreach ($property in $properties) +#if($property.isDateType) + if (params.entity.${property.name}) { + params.entity.${property.name} = new Date(params.entity.${property.name}); + } +#end +#end + $scope.entity = params.entity; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = params.options${property.name}; +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/index.html.template new file mode 100644 index 00000000000..05b17a7951a --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/index.html.template @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#end +#end +
+
+
+ + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/view.extension.template new file mode 100644 index 00000000000..ec6b82a3c18 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-window/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/view.js.template new file mode 100644 index 00000000000..f10442fcfcc --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/dialog-window/view.js.template @@ -0,0 +1,17 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-details', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-window/index.html', + perspectiveName: 'Reports' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/index.html.template new file mode 100644 index 00000000000..b8844bd17ca --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/index.html.template @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + {{'$projectName:${tprefix}.defaults.items' | t}} + + + + + + + +#foreach ($property in $properties) +#if($property.widgetIsMajor) + +#end +#end + + + + + + + + +#foreach ($property in $properties) +#if($property.widgetIsMajor) +#if($property.widgetType == "DROPDOWN") + +#elseif($property.widgetType == "EMAIL") + +#elseif($property.widgetType == "URL") + +#elseif($property.widgetType == "TEL") + +#elseif($property.widgetType == "COLOR") + +#elseif($property.widgetType == "WEEK") + +#elseif($property.widgetType == "MONTH") + +#elseif($property.widgetType == "TIME") + +#elseif($property.widgetType == "DATETIME-LOCAL") + +#elseif($property.widgetType == "DATE") + +#elseif($property.widgetType == "CHECKBOX") + +#else + +#end +#end +#end + + + +
{{ '$projectName:${tprefix}.t.$property.dataName' | t:'$property.name' }}
{{'$projectName:${tprefix}.messages.noData' | t}}
+ {{options${property.name}Value(next.${property.name})}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + + + + + + + + + + + + + + + {{next.${property.name}}} + + + + + + + + + + +
+
+ + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/view.extension.template new file mode 100644 index 00000000000..131c0d28481 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/view.js", + "extensionPoint": "application-reports", + "description": "${projectName} - Application View"#if($perspectiveRole || $roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/view.js.template new file mode 100644 index 00000000000..35a6d21a2e2 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report-table/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}', + label: '${name}', + translation: { + key: '$projectName:${tprefix}.t.$dataName', + }, + region: 'center', + lazyLoad: true, + autoFocusTab: false, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/Reports/${name}/index.html', + perspectiveName: 'Reports' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/controller.js.template new file mode 100644 index 00000000000..409513a3607 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/controller.js.template @@ -0,0 +1,217 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end EntityService, LocaleService, Extensions) => { + const Dialogs = new DialogHub(); + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 20; + + //-----------------Custom Actions-------------------// + Extensions.getWindows(['${projectName}-custom-action']).then((response) => { + $scope.pageActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && (e.type === 'page' || e.type === undefined)); + $scope.entityActions = response.data.filter(e => e.perspective === '${perspectiveName}' && e.view === '${name}' && e.type === 'entity'); + }); + + $scope.triggerPageAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + params: { + filterEntity: $scope.filterEntity, + #if($hasDropdowns) + #foreach ($property in $properties) + #if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, + #end + #end + #end + }, + maxWidth: action.maxWidth, + maxHeight: action.maxHeight, + closeButton: true, + }); + }; + + $scope.triggerEntityAction = (action) => { + Dialogs.showWindow({ + hasHeader: true, + title: LocaleService.t(action.translation.key, action.translation.options, action.label), + path: action.path, + params: { + id: $scope.entity.${primaryKeysString} + }, + closeButton: true, + }); + }; + //-----------------Custom Actions-------------------// + + function resetPagination() { + $scope.dataPage = 1; + $scope.dataCount = 0; + $scope.dataLimit = 20; + } + resetPagination(); + + //-----------------Events-------------------// + Dialogs.addMessageListener({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', handler: (data) => { + resetPagination(); + $scope.filter = data.filter; + $scope.filterEntity = data.entity; + $scope.loadPage($scope.dataPage, $scope.filter); + }}); + //-----------------Events-------------------// + + $scope.loadPage = (pageNumber, filter) => { + if (!filter && $scope.filter) { + filter = $scope.filter; + } + $scope.dataPage = pageNumber; + EntityService.count(filter).then((resp) => { + if (resp.data) { + $scope.dataCount = resp.data.count; + } + let offset = (pageNumber - 1) * $scope.dataLimit; + let limit = $scope.dataLimit; + let request; + if (filter) { + if (!filter.$filter) { + filter.$filter = {}; + } + filter.$filter.offset = offset; + filter.$filter.limit = limit; + request = EntityService.search(filter); + } else { + request = EntityService.list(offset, limit); + } + request.then((response) => { +#if($hasDates) + response.data.forEach(e => { +#foreach ($property in $properties) +#if($property.isDateType) + if (e.${property.name}) { + e.${property.name} = new Date(e.${property.name}); + } +#end +#end + }); + +#end + $scope.data = response.data; + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToCount', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + $scope.loadPage($scope.dataPage, $scope.filter); + + $scope.selectEntity = (entity) => { + $scope.selectedEntity = entity; + }; + + $scope.openDetails = (entity) => { + $scope.selectedEntity = entity; + Dialogs.showWindow({ + id: '${name}-Report-details', + params: { + action: "select", + entity: entity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + }); + }; + + $scope.openFilter = () => { + Dialogs.showWindow({ + id: '${name}-Report-filter', + params: { + entity: $scope.filterEntity, +#if($hasDropdowns) +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + options${property.name}: $scope.options${property.name}, +#end +#end +#end + }, + }); + }; +#if($hasDropdowns) + + //----------------Dropdowns-----------------// +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = []; +#end +#end +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + + ${dollar}http.get('${property.widgetDropdownControllerUrl}').then((response) => { + ${dollar}scope.options${property.name} = response.data.map(e => ({ + value: e.${property.widgetDropDownKey}, + text: e.${property.widgetDropDownValue} + })); + }, (error) => { + console.error(error); + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: '${property.name}', + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLoad', { message: message }), + type: AlertTypes.Error + }); + }); +#end +#end +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = (optionKey) => { +#if($property.widgetDropDownMultiSelect) + const values = []; + if (Array.isArray(optionKey)) { + optionKey = optionKey.join(); + } + optionKey.split(',').map(e => parseInt(e)).forEach(key => { + const found = ${dollar}scope.options${property.name}.find(e => e.value === key); + if (found) { + values.push(found.text); + } + }); + return values.join(', '); +#else + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; +#end + }; +#end +#end + //----------------Dropdowns-----------------// +#end + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/controller.js.template new file mode 100644 index 00000000000..ce7b88fca07 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/controller.js.template @@ -0,0 +1,92 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, ViewParameters) => { + const Dialogs = new DialogHub(); + $scope.entity = {}; + $scope.forms = { + details: {}, + }; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { +#foreach ($property in $properties) +#if($property.isDateType) + if (params?.entity?.${property.name}From) { + params.entity.${property.name}From = new Date(params.entity.${property.name}From); + } + if (params?.entity?.${property.name}To) { + params.entity.${property.name}To = new Date(params.entity.${property.name}To); + } +#end +#end + $scope.entity = params.entity ?? {}; + $scope.selectedMainEntityKey = params.selectedMainEntityKey; + $scope.selectedMainEntityId = params.selectedMainEntityId; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = params.options${property.name}; +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } + + $scope.filter = () => { + let entity = $scope.entity; + const filter = { + $filter: { + conditions: [], + sorts: [], + limit: 20, + offset: 0 + } + }; +#foreach ($property in $properties) +#if($property.dataTypeTypescript == 'number') + if (entity.${property.name} !== undefined) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'boolean') + if (entity.${property.name} !== undefined && entity.is${property.name}Indeterminate === false) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'string') + if (entity.${property.name}) { + const condition = { propertyName: '${property.name}', operator: 'LIKE', value: `%$dollar{entity.${property.name}}%` }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'Date') + if (entity.${property.name}From) { + const condition = { propertyName: '${property.name}', operator: 'GE', value: entity.${property.name}From }; + filter.$filter.conditions.push(condition); + } + if (entity.${property.name}To) { + const condition = { propertyName: '${property.name}', operator: 'LE', value: entity.${property.name}To }; + filter.$filter.conditions.push(condition); + } +#end +#end + Dialogs.postMessage({ topic: '${projectName}.${perspectiveName}.${name}.entitySearch', data: { + entity: entity, + filter: filter + } }); + $scope.cancel(); + }; + + $scope.resetFilter = () => { + $scope.entity = {}; + $scope.filter(); + }; + + $scope.cancel = () => { + Dialogs.closeWindow({ id: '${name}-Report-filter' }); + }; + + $scope.clearErrorMessage = () => { + $scope.errorMessage = null; + }; +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/index.html.template new file mode 100644 index 00000000000..50d0faa8cff --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/index.html.template @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + {{ errorMessage }} + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.defaults.from' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+ {{ '$projectName:${tprefix}.defaults.to' | t:{'text':'$t($projectName:${tprefix}.t.$property.dataName)'} }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + + + +
+
+#end +#end +#end +
+
+
+ + + + + + + + + + + + + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/view.extension.template new file mode 100644 index 00000000000..ad430eb623b --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-filter/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/view.js.template new file mode 100644 index 00000000000..e4eedc0a0bb --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-filter/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-Report-filter', + label: '${name} Report Filter', + translation: { + key: '$projectName:${tprefix}.extName', + options: { + content: '$t($projectName:${tprefix}.t.$dataName) $t($projectName:${tprefix}.defaults.reportFilter)', + } + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-filter/index.html', + perspectiveName: 'Reports' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/controller.js.template new file mode 100644 index 00000000000..cf66ad8d145 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/controller.js.template @@ -0,0 +1,130 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) + .config(['EntityServiceProvider', (EntityServiceProvider) => { + EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller'; + }]) + .controller('PageController', ($scope, EntityService, LocaleService, ViewParameters) => { + const Dialogs = new DialogHub(); + let params = ViewParameters.get(); + if (Object.keys(params).length) { + const filterEntity = params.filterEntity ?? {}; + + const filter = { + $filter: { + conditions: [], + sorts: [], + limit: 20, + offset: 0 + } + }; +#foreach ($property in $properties) +#if($property.dataTypeTypescript == 'number') + if (entity.${property.name} !== undefined) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'boolean') + if (entity.${property.name} !== undefined && entity.is${property.name}Indeterminate === false) { + const condition = { propertyName: '${property.name}', operator: 'EQ', value: entity.${property.name} }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'string') + if (entity.${property.name}) { + const condition = { propertyName: '${property.name}', operator: 'LIKE', value: `%$dollar{entity.${property.name}}%` }; + filter.$filter.conditions.push(condition); + } +#elseif($property.dataTypeTypescript == 'Date') + if (entity.${property.name}From) { + const condition = { propertyName: '${property.name}', operator: 'GE', value: entity.${property.name}From }; + filter.$filter.conditions.push(condition); + } + if (entity.${property.name}To) { + const condition = { propertyName: '${property.name}', operator: 'LE', value: entity.${property.name}To }; + filter.$filter.conditions.push(condition); + } +#end +#end + + $scope.filter = filter; + + #foreach ($property in $properties) + #if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = params.options${property.name}; + #if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } + #end + #end + #end + } + + $scope.loadPage = (filter) => { + if (!filter && $scope.filter) { + filter = $scope.filter; + } + let request; + if (filter) { + request = EntityService.search(filter); + } else { + request = EntityService.list(); + } + request.then((response) => { +#if($hasDates) + response.data.forEach(e => { +#foreach ($property in $properties) +#if($property.isDateType) + if (e.${property.name}) { + e.${property.name} = new Date(e.${property.name}); + } +#end +#end + }); + +#end + $scope.data = response.data; + setTimeout(() => { + window.print(); + }, 250); + }, (error) => { + const message = error.data ? error.data.message : ''; + Dialogs.showAlert({ + title: LocaleService.t('$projectName:${tprefix}.t.${dataName}'), + message: LocaleService.t('$projectName:${tprefix}.messages.error.unableToLF', { name: '$t($projectName:${tprefix}.t.${dataName})', message: message }), + type: AlertTypes.Error + }); + console.error('EntityService:', error); + }); + }; + $scope.loadPage($scope.filter); + +#foreach ($property in $properties) + #if($property.widgetType == "DROPDOWN") + ${dollar}scope.options${property.name}Value = (optionKey) => { + #if($property.widgetDropDownMultiSelect) + const values = []; + if (Array.isArray(optionKey)) { + optionKey = optionKey.join(); + } + optionKey.split(',').map(e => parseInt(e)).forEach(key => { + const found = ${dollar}scope.options${property.name}.find(e => e.value === key); + if (found) { + values.push(found.text); + } + }); + return values.join(', '); + #else + for (let i = 0; i < ${dollar}scope.options${property.name}.length; i++) { + if (${dollar}scope.options${property.name}[i].value === optionKey) { + return ${dollar}scope.options${property.name}[i].text; + } + } + return null; + #end + }; + #end +#end + window.onafterprint = () => { + Dialogs.closeWindow({ path: viewData.path }); + } + }); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/index.html.template new file mode 100644 index 00000000000..8df0de7f828 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/index.html.template @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + {{ '$projectName:${tprefix}.defaults.reportTitle' | t:{'name':'$name'} }} + + + + + + #foreach ($property in $properties) + #if(!$property.dataAutoIncrement) + + #end + #end + + + + + + + + #foreach ($property in $properties) + #if(!$property.dataAutoIncrement && $property.widgetIsMajor) + #if($property.widgetType == "DROPDOWN") + + #elseif($property.widgetType == "EMAIL") + + #elseif($property.widgetType == "URL") + + #elseif($property.widgetType == "TEL") + + #elseif($property.widgetType == "COLOR") + + #elseif($property.widgetType == "WEEK") + + #elseif($property.widgetType == "MONTH") + + #elseif($property.widgetType == "TIME") + + #elseif($property.widgetType == "DATETIME-LOCAL") + + #elseif($property.widgetType == "DATE") + + #elseif($property.widgetType == "CHECKBOX") + + #else + + #end + #end + #end + + +
{{ '$projectName:${tprefix}.t.$property.dataName' | t:'$property.name' }}
{{'$projectName:${tprefix}.messages.noData' | t}}
{{options${property.name}Value(next.${property.name})}} + {{next.${property.name}}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + + + + + + + + + + + + + + + {{next.${property.name}}}
+
+ + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/print.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/print.extension.template new file mode 100644 index 00000000000..58d876e1670 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/print.extension.template @@ -0,0 +1,6 @@ +{ + "extensionPoint": "${projectName}-custom-action", + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-print/print.js", + "description": "Print ${name} Report"#if($perspectiveRole || $roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/print.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/print.js.template new file mode 100644 index 00000000000..f7e2db83111 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-print/print.js.template @@ -0,0 +1,15 @@ +const viewData = { + id: '{{projectName}}-Reports-{{name}}-print', + label: 'Print', + translation: { + key: '$projectName:${tprefix}.defaults.print', + }, + path: '/services/web/{{projectName}}/gen/{{genFolderName}}/ui/Reports/{{name}}/dialog-print/index.html', + perspective: 'Reports', + view: '{{name}}', + type: 'page', + order: 10 +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/controller.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/controller.js.template new file mode 100644 index 00000000000..3f33cda3422 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/controller.js.template @@ -0,0 +1,28 @@ +#set($dollar = '$') +angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, ViewParameters) => { + $scope.entity = {}; + + let params = ViewParameters.get(); + if (Object.keys(params).length) { + $scope.action = 'select'; + +#foreach ($property in $properties) +#if($property.isDateType) + if (params.entity.${property.name}) { + params.entity.${property.name} = new Date(params.entity.${property.name}); + } +#end +#end + $scope.entity = params.entity; +#foreach ($property in $properties) +#if($property.widgetType == "DROPDOWN") + $scope.options${property.name} = params.options${property.name}; +#if($property.widgetDropDownMultiSelect) + if (${dollar}scope.entity.${property.name}) { + ${dollar}scope.entity.${property.name} = ${dollar}scope.entity.${property.name}.split(',').map(e => parseInt(e)); + } +#end +#end +#end + } +}); \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/index.html.template new file mode 100644 index 00000000000..016cf6a9384 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/index.html.template @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement) +#if($property.widgetType == "DROPDOWN") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "CHECKBOX") + +
+
+ + {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+#elseif($property.widgetType == "COLOR") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "NUMBER") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "MONTH") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "WEEK") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TIME") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATETIME-LOCAL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "DATE") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEXTAREA") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#elseif($property.widgetType == "TEL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#elseif($property.widgetType == "URL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#elseif($property.widgetType == "EMAIL") + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ {{entity.${property.name}}} +
+
+#else + +
+ {{ '$projectName:${tprefix}.t.$property.dataName' | t }} +
+
+ + +
+
+#end +#end +#end +
+
+
+ + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/view.extension.template new file mode 100644 index 00000000000..ec6b82a3c18 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-window/view.js", + "extensionPoint": "application-windows", + "description": "${projectName} - Application Dialog Window"#if($perspectiveRole || $roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/view.js.template new file mode 100644 index 00000000000..a42c6ac8b21 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/dialog-window/view.js.template @@ -0,0 +1,20 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}-Report-details', + label: '${name} Report', + translation: { + key: '$projectName:${tprefix}.defaults.reportTitle', + options: { + name: '$t($projectName:${tprefix}.t.$dataName)', + } + }, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/Reports/${name}/dialog-window/index.html', + perspectiveName: 'Reports' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/index.html.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/index.html.template new file mode 100644 index 00000000000..ca42f89ab0f --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/index.html.template @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + {{'$projectName:${tprefix}.defaults.items' | t}} + + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.widgetIsMajor) + +#end +#end + + + + + + + + +#foreach ($property in $properties) +#if(!$property.dataAutoIncrement && $property.widgetIsMajor) +#if($property.widgetType == "DROPDOWN") + +#elseif($property.widgetType == "EMAIL") + +#elseif($property.widgetType == "URL") + +#elseif($property.widgetType == "TEL") + +#elseif($property.widgetType == "COLOR") + +#elseif($property.widgetType == "WEEK") + +#elseif($property.widgetType == "MONTH") + +#elseif($property.widgetType == "TIME") + +#elseif($property.widgetType == "DATETIME-LOCAL") + +#elseif($property.widgetType == "DATE") + +#elseif($property.widgetType == "CHECKBOX") + +#else + +#end +#end +#end + + + +
{{ '$projectName:${tprefix}.t.$property.dataName' | t:'$property.name' }}
{{'$projectName:${tprefix}.messages.noData' | t}}
+ {{options${property.name}Value(next.${property.name})}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + {{next.${property.name}}} + + + + + + + + + + + + + + + + {{next.${property.name}}} + + + + + + + + + + + +
+
+ + + + + + + diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/view.extension.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/view.extension.template new file mode 100644 index 00000000000..131c0d28481 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/view.extension.template @@ -0,0 +1,6 @@ +{ + "module": "${projectName}/gen/${genFolderName}/ui/Reports/${name}/view.js", + "extensionPoint": "application-reports", + "description": "${projectName} - Application View"#if($perspectiveRole || $roleRead), + "role": "#if($perspectiveRole)${perspectiveRole},#end#if($roleRead)${roleRead}#end"#end +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/view.js.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/view.js.template new file mode 100644 index 00000000000..043208bbb51 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/perspective/report/view.js.template @@ -0,0 +1,23 @@ +/* + * Generated by Eclipse Dirigible based on model and template. + * + * Do not modify the content as it may be re-generated again. + */ +const viewData = { + id: '${name}Report', + label: '${name} Report', + translation: { + key: '$projectName:${tprefix}.defaults.reportTitle', + options: { + name: '$t($projectName:${tprefix}.t.$dataName)', + } + }, + region: 'center', + lazyLoad: true, + autoFocusTab: false, + path: '/services/web/${projectName}/gen/${genFolderName}/ui/Reports/${name}/index.html', + perspectiveName: 'Reports' +}; +if (typeof exports !== 'undefined') { + exports.getView = () => viewData; +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/translations-report.json.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/translations-report.json.template new file mode 100644 index 00000000000..9c057188f27 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/translations-report.json.template @@ -0,0 +1,30 @@ +{ + "aria": { + "tableRowMenu": "Table Row Menu", + "tableRowMenuBtn": "Table Row Menu Button" + }, + "messages": { + "error" : { + "incorrectInput": "Incorrect Input", + "unableToLF": "Unable to list/filter {{name}}: '{{message}}'", + "unableToCount": "Unable to count {{name}}: '{{message}}'" + }, + "inputEnter": "Enter {{name}}...", + "noData": "No data available." + }, + "defaults": { + "filter": "Filter", + "print": "Print", + "reset": "Reset", + "cancel": "Cancel", + "items": "Items", + "formGrpFilter": "{{name}} Filter", + "formHeadSelect": "{{name}} Details", + "reportTitle": "{{name}} Report", + "reportFilter": "Report Filter", + "viewDetails": "View Details", + "export": "Export" + }, + "extName": "{{content}}", + "t": {} +} \ No newline at end of file diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/translations.json.template b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/translations.json.template new file mode 100644 index 00000000000..68ad078f4d3 --- /dev/null +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/ui/translations.json.template @@ -0,0 +1,68 @@ +{ + "aria": { + "showHide": "show/hide {{name}} options", + "options": "{{name}} options", + "tableRowMenu": "Table Row Menu", + "tableRowMenuBtn": "Table Row Menu Button", + "headerMenu": "Header Menu", + "headerMenuBtn": "Header Menu Button", + "addEntity": "add entity", + "editEntity": "edit entity", + "deleteEntity": "delete entity" + }, + "state": { + "busy": "Loading..." + }, + "messages": { + "error" : { + "incorrectInput": "Incorrect Input", + "loading": "Encounterd an error while loading", + "unableToCreate": "Unable to create {{name}}: '{{message}}'", + "unableToUpdate": "Unable to update {{name}}: '{{message}}'", + "unableToDelete": "Unable to delete {{name}}: '{{message}}'", + "unableToLoad": "Unable to load data: '{{message}}'", + "unableToLF": "Unable to list/filter {{name}}: '{{message}}'", + "unableToCount": "Unable to count {{name}}: '{{message}}'", + "pattern": "The value doesn't match the required pattern: {{rule}}", + "lengthMinMax": "Value must be between {{min}} and {{max}} characters long", + "lengthMin": "Value must not be less than {{min}} characters", + "lengthMax": "Value must not be more than {{max}} characters" + }, + "propertySuccessfullyCreated": "{{name}} successfully created", + "propertySuccessfullyUpdated": "{{name}} successfully updated", + "inputSearch": "Search {{name}}...", + "inputEnter": "Enter {{name}}...", + "noData": "No data available.", + "deleteConfirm": "Are you sure you want to delete {{name}}? This action cannot be undone.", + "detailSelectRecord": "Select a record to get a list of it's details." + }, + "defaults": { + "yes": "Yes", + "no": "No", + "add": "Add", + "refresh": "Refresh", + "to": "To {{text}}", + "from": "From {{text}}", + "filter": "Filter", + "print": "Print", + "reset": "Reset", + "create": "Create", + "edit": "Edit", + "update": "Update", + "delete": "Delete", + "cancel": "Cancel", + "items": "Items", + "description": "Description", + "formGrpFilter": "{{name}} Filter", + "formHeadSelect": "{{name}} Details", + "formHeadCreate": "Create {{name}}", + "formHeadUpdate": "Update {{name}}", + "reportTitle": "{{name}} Report", + "reportFilter": "Report Filter", + "viewDetails": "View Details", + "deleteTitle": "Delete {{name}}?", + "loadMore": "Load More..." + }, + "extName": "{{content}}", + "t": {} +} \ No newline at end of file diff --git a/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java index 3861790f317..02d906089c4 100644 --- a/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java +++ b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java @@ -116,13 +116,17 @@ public BookRepository() { import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; + import java.util.LinkedHashMap; import java.util.List; import java.util.Map; + import java.util.Set; @Controller @Documentation("java-template-it - Book Controller") public class BookController { + private static final Set FILTER_FIELDS = Set.of("id", "title"); + @Inject private BookRepository repository; @@ -141,6 +145,18 @@ public Map count() { return Map.of("count", repository.count()); } + @Post("/count") + @Documentation("Count Book with filter") + public Map countWithFilter(@Body Map filter) { + return Map.of("count", (long) runFilter(filter).size()); + } + + @Post("/search") + @Documentation("Search Book") + public List search(@Body Map filter) { + return runFilter(filter); + } + @Get("/{id}") @Documentation("Get Book by id") public BookEntity getById(@PathParam("id") Integer id) { @@ -169,6 +185,25 @@ public void deleteById(@PathParam("id") Integer id) { } repository.deleteById(id); } + + private List runFilter(Map filter) { + StringBuilder hql = new StringBuilder("from BookEntity e"); + Map params = new LinkedHashMap<>(); + if (filter != null && filter.get("equals") instanceof Map equals) { + boolean first = true; + for (Map.Entry entry : equals.entrySet()) { + String field = String.valueOf(entry.getKey()); + if (!FILTER_FIELDS.contains(field)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown filter field: " + field); + } + String paramName = "p" + params.size(); + hql.append(first ? " where e." : " and e.").append(field).append(" = :").append(paramName); + params.put(paramName, entry.getValue()); + first = false; + } + } + return repository.query(hql.toString(), params); + } } """; @@ -234,6 +269,35 @@ void generated_dao_and_controller_serve_crud_over_http() { .body(containsString("count")), ASSERTION_TIMEOUT_SECONDS); + // POST /search with a known field returns the matching row. + restAssuredExecutor.execute(() -> given().when() + .contentType(ContentType.JSON) + .body("{\"equals\":{\"title\":\"Dune Messiah\"}}") + .post(CONTROLLER_BASE + "/search") + .then() + .statusCode(200) + .body(containsString("Dune Messiah")), + ASSERTION_TIMEOUT_SECONDS); + + // POST /count with the same filter returns at least 1. + restAssuredExecutor.execute(() -> given().when() + .contentType(ContentType.JSON) + .body("{\"equals\":{\"title\":\"Dune Messiah\"}}") + .post(CONTROLLER_BASE + "/count") + .then() + .statusCode(200) + .body(containsString("count")), + ASSERTION_TIMEOUT_SECONDS); + + // POST /search with an unknown field is rejected by the SQL-injection allow-list. + restAssuredExecutor.execute(() -> given().when() + .contentType(ContentType.JSON) + .body("{\"equals\":{\"nope\":\"x\"}}") + .post(CONTROLLER_BASE + "/search") + .then() + .statusCode(400), + ASSERTION_TIMEOUT_SECONDS); + // DELETE removes the row; subsequent GET returns 404. restAssuredExecutor.execute(() -> given().when() .delete(CONTROLLER_BASE + "/" + createdId) From be16434ff70044620acd1d9c422fc4f5175acd80 Mon Sep 17 00:00:00 2001 From: ThuF Date: Fri, 22 May 2026 15:27:17 +0300 Subject: [PATCH 3/5] Make EDM dropdown widget Java-aware --- .../template/template.js | 1 + .../api/EntityController.java.template | 42 +++++++++-- .../template/template.js | 1 + .../template/parameterUtils.js | 32 ++++----- .../integration/tests/api/JavaTemplateIT.java | 71 +++++++++++++++++-- 5 files changed, 121 insertions(+), 26 deletions(-) diff --git a/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.js b/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.js index 70b05e32380..1e03b5ad84d 100644 --- a/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.js +++ b/components/template/template-application-angular-java/src/main/resources/META-INF/dirigible/template-application-angular-java/template/template.js @@ -11,6 +11,7 @@ import * as parameterUtils from "service-generate/template/parameterUtils"; export function generate(model, parameters) { model = JSON.parse(model).model; let templateSources = getTemplate(parameters).sources; + parameters.javaRuntime = true; parameterUtils.process(model, parameters); return generateUtils.generateFiles(model, parameters, templateSources); }; diff --git a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template index 29a0de56cb7..4aec0e231ed 100644 --- a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template +++ b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template @@ -28,8 +28,10 @@ import org.springframework.web.server.ResponseStatusException; import jakarta.servlet.http.HttpServletRequest; +import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -163,21 +165,51 @@ public class ${name}Controller { private List<${name}Entity> runFilter(Map filter) { StringBuilder hql = new StringBuilder("from ${name}Entity e"); Map params = new LinkedHashMap<>(); + boolean first = true; if (filter != null && filter.get("equals") instanceof Map equals) { - boolean first = true; for (Map.Entry entry : equals.entrySet()) { - String field = String.valueOf(entry.getKey()); - if (!FILTER_FIELDS.contains(field)) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown filter field: " + field); - } + String field = requireKnownField(String.valueOf(entry.getKey())); String paramName = "p" + params.size(); hql.append(first ? " where e." : " and e.").append(field).append(" = :").append(paramName); params.put(paramName, entry.getValue()); first = false; } } + if (filter != null && filter.get("conditions") instanceof List conditions) { + for (Object raw : conditions) { + if (!(raw instanceof Map condition)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid filter condition"); + } + String field = requireKnownField(String.valueOf(condition.get("propertyName"))); + String operator = String.valueOf(condition.get("operator")).toUpperCase(Locale.ROOT); + Object value = condition.get("value"); + String paramName = "p" + params.size(); + String clause = switch (operator) { + case "EQ" -> "e." + field + " = :" + paramName; + case "IN" -> { + if (!(value instanceof Collection)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "IN value must be a list for field: " + field); + } + yield "e." + field + " in (:" + paramName + ")"; + } + case "LIKE" -> "e." + field + " like :" + paramName; + default -> throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unsupported operator: " + operator); + }; + hql.append(first ? " where " : " and ").append(clause); + params.put(paramName, value); + first = false; + } + } return repository.query(hql.toString(), params); } + + private static String requireKnownField(String field) { + if (!FILTER_FIELDS.contains(field)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown filter field: " + field); + } + return field; + } #if($needsRoles) private void checkPermissions(String op, HttpServletRequest request) { diff --git a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.js b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.js index b5f49688dcc..b50d94650fd 100644 --- a/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.js +++ b/components/template/template-application-ui-angular-java/src/main/resources/META-INF/dirigible/template-application-ui-angular-java/template/template.js @@ -11,6 +11,7 @@ import * as parameterUtils from "service-generate/template/parameterUtils"; export function generate(model, parameters) { model = JSON.parse(model).model; let templateSources = getTemplate(parameters).sources; + parameters.javaRuntime = true; parameterUtils.process(model, parameters) return generateUtils.generateFiles(model, parameters, templateSources); }; diff --git a/components/ui/service-generate/src/main/resources/META-INF/dirigible/service-generate/template/parameterUtils.js b/components/ui/service-generate/src/main/resources/META-INF/dirigible/service-generate/template/parameterUtils.js index 3f17216602d..a561b90e2ab 100644 --- a/components/ui/service-generate/src/main/resources/META-INF/dirigible/service-generate/template/parameterUtils.js +++ b/components/ui/service-generate/src/main/resources/META-INF/dirigible/service-generate/template/parameterUtils.js @@ -136,27 +136,27 @@ export function process(model, parameters) { }) if (p.widgetType == "DROPDOWN") { - let projectNameString = `/services/ts/${parameters.projectName}/gen/${parameters.genFolderName}/api/${p.relationshipEntityPerspectiveName}/${p.relationshipEntityName}Service.ts`; - let projectNameControllerString = `/services/ts/${parameters.projectName}/gen/${parameters.genFolderName}/api/${p.relationshipEntityPerspectiveName}/${p.relationshipEntityName}Controller.ts`; - e.hasDropdowns = true; + let targetProject = parameters.projectName; + let targetGenFolder = parameters.genFolderName; if (e.referencedProjections.length !== 0) { - let foundReferenceProjection = false; - e.referencedProjections.forEach(referencedProjection => { - if (referencedProjection.name === p.relationshipEntityName && !foundReferenceProjection) { - p.widgetDropdownUrl = `/services/ts/${referencedProjection.project}/gen/${referencedProjection.genFolderName}/api/${p.relationshipEntityPerspectiveName}/${p.relationshipEntityName}Service.ts`; - p.widgetDropdownControllerUrl = `/services/ts/${referencedProjection.project}/gen/${referencedProjection.genFolderName}/api/${p.relationshipEntityPerspectiveName}/${p.relationshipEntityName}Controller.ts`; - foundReferenceProjection = true; - } - }); - if (!foundReferenceProjection) { - p.widgetDropdownUrl = projectNameString; - p.widgetDropdownControllerUrl = projectNameControllerString; + const referencedProjection = e.referencedProjections.find(rp => rp.name === p.relationshipEntityName); + if (referencedProjection) { + targetProject = referencedProjection.project; + targetGenFolder = referencedProjection.genFolderName; } + } + + if (parameters.javaRuntime) { + const javaGen = sanitizeJavaIdentifier(targetGenFolder); + const javaPerspective = sanitizeJavaIdentifier(p.relationshipEntityPerspectiveName); + const javaUrl = `/services/java/${targetProject}/gen/${javaGen}/api/${javaPerspective}/${p.relationshipEntityName}Controller`; + p.widgetDropdownUrl = javaUrl; + p.widgetDropdownControllerUrl = javaUrl; } else { - p.widgetDropdownUrl = projectNameString; - p.widgetDropdownControllerUrl = projectNameControllerString; + p.widgetDropdownUrl = `/services/ts/${targetProject}/gen/${targetGenFolder}/api/${p.relationshipEntityPerspectiveName}/${p.relationshipEntityName}Service.ts`; + p.widgetDropdownControllerUrl = `/services/ts/${targetProject}/gen/${targetGenFolder}/api/${p.relationshipEntityPerspectiveName}/${p.relationshipEntityName}Controller.ts`; } } }); diff --git a/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java index 02d906089c4..ee00c807ef1 100644 --- a/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java +++ b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java @@ -116,8 +116,10 @@ public BookRepository() { import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; + import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; + import java.util.Locale; import java.util.Map; import java.util.Set; @@ -189,21 +191,51 @@ public void deleteById(@PathParam("id") Integer id) { private List runFilter(Map filter) { StringBuilder hql = new StringBuilder("from BookEntity e"); Map params = new LinkedHashMap<>(); + boolean first = true; if (filter != null && filter.get("equals") instanceof Map equals) { - boolean first = true; for (Map.Entry entry : equals.entrySet()) { - String field = String.valueOf(entry.getKey()); - if (!FILTER_FIELDS.contains(field)) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown filter field: " + field); - } + String field = requireKnownField(String.valueOf(entry.getKey())); String paramName = "p" + params.size(); hql.append(first ? " where e." : " and e.").append(field).append(" = :").append(paramName); params.put(paramName, entry.getValue()); first = false; } } + if (filter != null && filter.get("conditions") instanceof List conditions) { + for (Object raw : conditions) { + if (!(raw instanceof Map condition)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid filter condition"); + } + String field = requireKnownField(String.valueOf(condition.get("propertyName"))); + String operator = String.valueOf(condition.get("operator")).toUpperCase(Locale.ROOT); + Object value = condition.get("value"); + String paramName = "p" + params.size(); + String clause = switch (operator) { + case "EQ" -> "e." + field + " = :" + paramName; + case "IN" -> { + if (!(value instanceof Collection)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "IN value must be a list for field: " + field); + } + yield "e." + field + " in (:" + paramName + ")"; + } + case "LIKE" -> "e." + field + " like :" + paramName; + default -> throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unsupported operator: " + operator); + }; + hql.append(first ? " where " : " and ").append(clause); + params.put(paramName, value); + first = false; + } + } return repository.query(hql.toString(), params); } + + private static String requireKnownField(String field) { + if (!FILTER_FIELDS.contains(field)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown filter field: " + field); + } + return field; + } } """; @@ -298,6 +330,35 @@ void generated_dao_and_controller_serve_crud_over_http() { .statusCode(400), ASSERTION_TIMEOUT_SECONDS); + // POST /search with the conditions shape the dropdown widget sends (IN with a list). + restAssuredExecutor.execute(() -> given().when() + .contentType(ContentType.JSON) + .body("{\"conditions\":[{\"propertyName\":\"title\",\"operator\":\"IN\",\"value\":[\"Dune Messiah\",\"Foundation\"]}]}") + .post(CONTROLLER_BASE + "/search") + .then() + .statusCode(200) + .body(containsString("Dune Messiah")), + ASSERTION_TIMEOUT_SECONDS); + + // POST /search with a LIKE condition matches the row by pattern. + restAssuredExecutor.execute(() -> given().when() + .contentType(ContentType.JSON) + .body("{\"conditions\":[{\"propertyName\":\"title\",\"operator\":\"LIKE\",\"value\":\"Dune%\"}]}") + .post(CONTROLLER_BASE + "/search") + .then() + .statusCode(200) + .body(containsString("Dune Messiah")), + ASSERTION_TIMEOUT_SECONDS); + + // POST /search with an unsupported operator is rejected. + restAssuredExecutor.execute(() -> given().when() + .contentType(ContentType.JSON) + .body("{\"conditions\":[{\"propertyName\":\"title\",\"operator\":\"REGEX\",\"value\":\".*\"}]}") + .post(CONTROLLER_BASE + "/search") + .then() + .statusCode(400), + ASSERTION_TIMEOUT_SECONDS); + // DELETE removes the row; subsequent GET returns 404. restAssuredExecutor.execute(() -> given().when() .delete(CONTROLLER_BASE + "/" + createdId) From d988960112736fa0395b7e21a0bc3687939f9b52 Mon Sep 17 00:00:00 2001 From: ThuF Date: Fri, 22 May 2026 20:19:36 +0300 Subject: [PATCH 4/5] Use UserFacade in EntityController; accept .table identity alias --- .../data/structures/domain/TableColumn.java | 2 + .../synchronizer/SchemasSynchronizer.java | 9 +++ .../api/EntityController.java.template | 70 +++++++++---------- .../integration/tests/api/JavaTemplateIT.java | 39 +++++++++-- 4 files changed, 77 insertions(+), 43 deletions(-) diff --git a/components/data/data-structures/src/main/java/org/eclipse/dirigible/components/data/structures/domain/TableColumn.java b/components/data/data-structures/src/main/java/org/eclipse/dirigible/components/data/structures/domain/TableColumn.java index 67cf470e1fe..3c2da8188ad 100644 --- a/components/data/data-structures/src/main/java/org/eclipse/dirigible/components/data/structures/domain/TableColumn.java +++ b/components/data/data-structures/src/main/java/org/eclipse/dirigible/components/data/structures/domain/TableColumn.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; import jakarta.persistence.*; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; @@ -75,6 +76,7 @@ public class TableColumn { private boolean unique; @Column(name = "COLUMN_AUTOINCREMENT", columnDefinition = "BOOLEAN", nullable = true) @Expose + @SerializedName(value = "autoincrement", alternate = {"identity"}) private boolean autoincrement; /** The table. */ @ManyToOne(fetch = FetchType.EAGER, optional = false) diff --git a/components/data/data-structures/src/main/java/org/eclipse/dirigible/components/data/structures/synchronizer/SchemasSynchronizer.java b/components/data/data-structures/src/main/java/org/eclipse/dirigible/components/data/structures/synchronizer/SchemasSynchronizer.java index 58debcba973..273fdad904b 100644 --- a/components/data/data-structures/src/main/java/org/eclipse/dirigible/components/data/structures/synchronizer/SchemasSynchronizer.java +++ b/components/data/data-structures/src/main/java/org/eclipse/dirigible/components/data/structures/synchronizer/SchemasSynchronizer.java @@ -339,6 +339,15 @@ private static void setColumnAttributes(JsonObject column, TableColumn columnMod && column.get("nullable") .getAsBoolean()); + // The .table parser deserialises this field via Gson's @SerializedName(value="autoincrement", + // alternate={"identity"}); the .schema parser is hand-rolled and needs to honour both + // spellings explicitly. "identity" is the canonical name in every existing .schema fixture. + JsonElement identityElement = column.get("identity"); + if (identityElement == null || identityElement.isJsonNull()) { + identityElement = column.get("autoincrement"); + } + columnModel.setAutoincrement(identityElement != null && !identityElement.isJsonNull() && identityElement.getAsBoolean()); + String defaultValue = getJsonElementValue(column, "defaultValue", null); columnModel.setDefaultValue(defaultValue); diff --git a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template index 4aec0e231ed..9531ba0b7e8 100644 --- a/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template +++ b/components/template/template-application-rest-java/src/main/resources/META-INF/dirigible/template-application-rest-java/api/EntityController.java.template @@ -12,10 +12,10 @@ package gen.${javaGenFolderName}.api.${javaPerspectiveName}; import gen.${javaGenFolderName}.data.${javaPerspectiveName}.${name}Entity; import gen.${javaGenFolderName}.data.${javaPerspectiveName}.${name}Repository; +import org.eclipse.dirigible.components.api.security.UserFacade; import org.eclipse.dirigible.engine.java.annotations.Documentation; import org.eclipse.dirigible.engine.java.annotations.Inject; import org.eclipse.dirigible.engine.java.annotations.http.Body; -import org.eclipse.dirigible.engine.java.annotations.http.Context; import org.eclipse.dirigible.engine.java.annotations.http.Controller; import org.eclipse.dirigible.engine.java.annotations.http.Delete; import org.eclipse.dirigible.engine.java.annotations.http.Get; @@ -26,8 +26,6 @@ import org.eclipse.dirigible.engine.java.annotations.http.QueryParam; import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; -import jakarta.servlet.http.HttpServletRequest; - import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; @@ -47,11 +45,10 @@ public class ${name}Controller { @Get @Documentation("List ${name}") public List<${name}Entity> getAll(@QueryParam("$limit") Integer limit, - @QueryParam("$offset") Integer offset#if($needsRoles), - @Context HttpServletRequest request#end#if($layoutType == "MANAGE_DETAILS" || $layoutType == "LIST_DETAILS"), + @QueryParam("$offset") Integer offset#if($layoutType == "MANAGE_DETAILS" || $layoutType == "LIST_DETAILS"), @QueryParam("${masterEntityId}") String ${masterEntityId}#end) { #if($needsRoles) - checkPermissions("read", request); + checkPermissions("read"); #end int actualLimit = limit != null ? limit.intValue() : 20; int actualOffset = offset != null ? offset.intValue() : 0; @@ -68,64 +65,64 @@ public class ${name}Controller { List<${name}Entity> result = repository.findAll(actualLimit, actualOffset); #end #if($isEntityPropertySecurityEnabled) - result.forEach(e -> redactRead(e, request)); + result.forEach(this::redactRead); #end return result; } @Get("/count") @Documentation("Count ${name}") - public Map count(#if($needsRoles)@Context HttpServletRequest request#end) { + public Map count() { #if($needsRoles) - checkPermissions("read", request); + checkPermissions("read"); #end return Map.of("count", repository.count()); } @Post("/count") @Documentation("Count ${name} with filter") - public Map countWithFilter(@Body Map filter#if($needsRoles), @Context HttpServletRequest request#end) { + public Map countWithFilter(@Body Map filter) { #if($needsRoles) - checkPermissions("read", request); + checkPermissions("read"); #end return Map.of("count", (long) runFilter(filter).size()); } @Post("/search") @Documentation("Search ${name}") - public List<${name}Entity> search(@Body Map filter#if($needsRoles), @Context HttpServletRequest request#end) { + public List<${name}Entity> search(@Body Map filter) { #if($needsRoles) - checkPermissions("read", request); + checkPermissions("read"); #end List<${name}Entity> result = runFilter(filter); #if($isEntityPropertySecurityEnabled) - result.forEach(e -> redactRead(e, request)); + result.forEach(this::redactRead); #end return result; } @Get("/{id}") @Documentation("Get ${name} by id") - public ${name}Entity getById(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id#if($needsRoles), @Context HttpServletRequest request#end) { + public ${name}Entity getById(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id) { #if($needsRoles) - checkPermissions("read", request); + checkPermissions("read"); #end ${name}Entity entity = repository.findOne(id) .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "${name} not found")); #if($isEntityPropertySecurityEnabled) - redactRead(entity, request); + redactRead(entity); #end return entity; } @Post @Documentation("Create ${name}") - public ${name}Entity create(@Body ${name}Entity entity#if($needsRoles), @Context HttpServletRequest request#end) { + public ${name}Entity create(@Body ${name}Entity entity) { #if($needsRoles) - checkPermissions("write", request); + checkPermissions("write"); #end #if($isEntityPropertySecurityEnabled) - applyOnCreate(entity, request); + applyOnCreate(entity); #end validate(entity); return repository.save(entity); @@ -133,14 +130,14 @@ public class ${name}Controller { @Put("/{id}") @Documentation("Update ${name} by id") - public ${name}Entity update(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id, @Body ${name}Entity entity#if($needsRoles), @Context HttpServletRequest request#end) { + public ${name}Entity update(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id, @Body ${name}Entity entity) { #if($needsRoles) - checkPermissions("write", request); + checkPermissions("write"); #end #if($isEntityPropertySecurityEnabled) ${name}Entity existing = repository.findOne(id) .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "${name} not found")); - mergeWritable(existing, entity, request); + mergeWritable(existing, entity); validate(existing); return repository.update(existing); #else @@ -152,9 +149,9 @@ public class ${name}Controller { @Delete("/{id}") @Documentation("Delete ${name} by id") - public void deleteById(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id#if($needsRoles), @Context HttpServletRequest request#end) { + public void deleteById(@PathParam("id") #foreach($property in $properties)#if($property.dataPrimaryKey)${property.dataTypeJavaClass}#end#end id) { #if($needsRoles) - checkPermissions("write", request); + checkPermissions("write"); #end if (repository.findOne(id).isEmpty()) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "${name} not found"); @@ -188,8 +185,7 @@ public class ${name}Controller { case "EQ" -> "e." + field + " = :" + paramName; case "IN" -> { if (!(value instanceof Collection)) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, - "IN value must be a list for field: " + field); + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "IN value must be a list for field: " + field); } yield "e." + field + " in (:" + paramName + ")"; } @@ -212,19 +208,19 @@ public class ${name}Controller { } #if($needsRoles) - private void checkPermissions(String op, HttpServletRequest request) { + private void checkPermissions(String op) { #if($perspectiveRole) - if (!request.isUserInRole("${perspectiveRole}")) { + if (!UserFacade.isInRole("${perspectiveRole}")) { throw new ResponseStatusException(HttpStatus.FORBIDDEN); } #end #if($roleRead) - if ("read".equals(op) && !(request.isUserInRole("${roleRead}")#if($roleWrite) || request.isUserInRole("${roleWrite}")#end)) { + if ("read".equals(op) && !(UserFacade.isInRole("${roleRead}")#if($roleWrite) || UserFacade.isInRole("${roleWrite}")#end)) { throw new ResponseStatusException(HttpStatus.FORBIDDEN); } #end #if($roleWrite) - if ("write".equals(op) && !request.isUserInRole("${roleWrite}")) { + if ("write".equals(op) && !UserFacade.isInRole("${roleWrite}")) { throw new ResponseStatusException(HttpStatus.FORBIDDEN); } #end @@ -232,21 +228,21 @@ public class ${name}Controller { #end #if($isEntityPropertySecurityEnabled) - private void redactRead(${name}Entity entity, HttpServletRequest request) { + private void redactRead(${name}Entity entity) { #foreach ($property in $properties) #if($property.roleRead) - if (!request.isUserInRole("${property.roleRead}")) { + if (!UserFacade.isInRole("${property.roleRead}")) { entity.${property.name} = null; } #end #end } - private void mergeWritable(${name}Entity target, ${name}Entity input, HttpServletRequest request) { + private void mergeWritable(${name}Entity target, ${name}Entity input) { #foreach ($property in $properties) #if(!$property.dataPrimaryKey) #if($property.roleWrite) - if (request.isUserInRole("${property.roleWrite}")) { + if (UserFacade.isInRole("${property.roleWrite}")) { target.${property.name} = input.${property.name}; } #else @@ -256,10 +252,10 @@ public class ${name}Controller { #end } - private void applyOnCreate(${name}Entity entity, HttpServletRequest request) { + private void applyOnCreate(${name}Entity entity) { #foreach ($property in $properties) #if($property.roleWrite) - if (!request.isUserInRole("${property.roleWrite}")) { + if (!UserFacade.isInRole("${property.roleWrite}")) { entity.${property.name} = null; } #end diff --git a/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java index ee00c807ef1..b080a52ceb3 100644 --- a/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java +++ b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/JavaTemplateIT.java @@ -43,6 +43,8 @@ class JavaTemplateIT extends IntegrationTest { private static final String PROJECT = "java-template-it"; + private static final String TABLE_PATH = + IRepositoryStructure.PATH_REGISTRY_PUBLIC + "/" + PROJECT + "/gen/sample/data/books/Book.table"; private static final String ENTITY_PATH = IRepositoryStructure.PATH_REGISTRY_PUBLIC + "/" + PROJECT + "/gen/sample/data/books/BookEntity.java"; private static final String REPOSITORY_PATH = @@ -54,6 +56,28 @@ class JavaTemplateIT extends IntegrationTest { private static final long ASSERTION_TIMEOUT_SECONDS = 30; + private static final String TABLE_SOURCE = """ + { + "name": "JAVATEMPLATEIT_BOOK", + "type": "TABLE", + "columns": [ + { + "type": "INTEGER", + "primaryKey": true, + "identity": true, + "nullable": false, + "name": "BOOK_ID" + }, + { + "type": "VARCHAR", + "length": 40, + "nullable": false, + "name": "BOOK_TITLE" + } + ] + } + """; + private static final String ENTITY_SOURCE = """ package gen.sample.data.books; @@ -382,19 +406,22 @@ void generated_dao_and_controller_serve_crud_over_http() { } private void writeAll() { - write(ENTITY_PATH, ENTITY_SOURCE); - write(REPOSITORY_PATH, REPOSITORY_SOURCE); - write(CONTROLLER_PATH, CONTROLLER_SOURCE); + // .table artefact first so TableSynchronizer materialises JAVATEMPLATEIT_BOOK + // (with IDENTITY on BOOK_ID) before the Java entity is registered against it. + write(TABLE_PATH, TABLE_SOURCE, "application/json"); + write(ENTITY_PATH, ENTITY_SOURCE, "text/x-java"); + write(REPOSITORY_PATH, REPOSITORY_SOURCE, "text/x-java"); + write(CONTROLLER_PATH, CONTROLLER_SOURCE, "text/x-java"); synchronizationProcessor.forceProcessSynchronizers(); } - private void write(String path, String source) { - repository.createResource(path, source.getBytes(StandardCharsets.UTF_8), false, "text/x-java", true); + private void write(String path, String source, String contentType) { + repository.createResource(path, source.getBytes(StandardCharsets.UTF_8), false, contentType, true); } @AfterEach void cleanup() { - for (String path : List.of(ENTITY_PATH, REPOSITORY_PATH, CONTROLLER_PATH)) { + for (String path : List.of(TABLE_PATH, ENTITY_PATH, REPOSITORY_PATH, CONTROLLER_PATH)) { if (repository.hasResource(path)) { repository.removeResource(path); } From f7d9897c83da7c7a5a881ccce6caaa2949ee6818 Mon Sep 17 00:00:00 2001 From: ThuF Date: Sat, 23 May 2026 21:58:30 +0300 Subject: [PATCH 5/5] Advance IDENTITY counter after CSVIM bulk-load --- .../data/csvim/processor/CsvimProcessor.java | 97 +++++++++++ .../tests/api/CsvimIdentityRestartIT.java | 159 ++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/CsvimIdentityRestartIT.java diff --git a/components/data/data-csvim/src/main/java/org/eclipse/dirigible/components/data/csvim/processor/CsvimProcessor.java b/components/data/data-csvim/src/main/java/org/eclipse/dirigible/components/data/csvim/processor/CsvimProcessor.java index ad9d1c0a22f..a6536081e96 100644 --- a/components/data/data-csvim/src/main/java/org/eclipse/dirigible/components/data/csvim/processor/CsvimProcessor.java +++ b/components/data/data-csvim/src/main/java/org/eclipse/dirigible/components/data/csvim/processor/CsvimProcessor.java @@ -236,6 +236,13 @@ public void process(CsvFile csvFile, InputStream content, String dataSourceName) updateCsvRecords(connection, targetSchema, tableMetadata, recordsToUpdate, csvParser.getHeaderNames(), pkName, csvFile); } updateSequence(csvFile, connection, countAll); + if (countAll > 0) { + // CSV inserts always carry an explicit PK value; the DB's IDENTITY counter is therefore + // not advanced by the load. Bump it to MAX(col)+1 so a subsequent INSERT … DEFAULT + // (e.g. from a Hibernate @GeneratedValue(IDENTITY) entity) doesn't collide on the seeded + // rows. + restartIdentityColumns(dataSource, connection, targetSchema, tableName); + } } } @@ -281,6 +288,96 @@ public void updateSequence(CsvFile csvFile, Connection connection, int countAll) } } + /** + * Walks JDBC metadata for the freshly-loaded table, finds every {@code IS_AUTOINCREMENT == YES} + * column, and advances its internal counter to {@code MAX(col) + 1}. Most engines (H2, PostgreSQL, + * MSSQL, MySQL) do not auto-advance an identity counter when the INSERT supplies an explicit value, + * which leaves the next "generate-me-one" INSERT colliding with the seeded rows on PK = 1. + * + *

+ * Failures here are logged and swallowed — the CSV data is already persisted, and not every dialect + * supports identity restart in a portable way. Production traffic will surface the same collision + * the user already saw if the restart fails, but at least the seeded rows survive. + */ + private void restartIdentityColumns(DirigibleDataSource dataSource, Connection connection, String schema, String tableName) { + try (ResultSet cols = connection.getMetaData() + .getColumns(connection.getCatalog(), schema, tableName, "%")) { + while (cols.next()) { + if (!"YES".equalsIgnoreCase(cols.getString("IS_AUTOINCREMENT"))) { + continue; + } + String column = cols.getString("COLUMN_NAME"); + try { + long next = computeNextValue(connection, schema, tableName, column); + executeIdentityRestart(dataSource, connection, schema, tableName, column, next); + logger.info("Advanced IDENTITY counter on [{}.{}.{}] to [{}]", schema, tableName, column, next); + } catch (SQLException restartError) { + logger.warn("Failed to advance IDENTITY counter on [{}.{}.{}]: {}", schema, tableName, column, + restartError.getMessage()); + } + } + } catch (SQLException metadataError) { + logger.warn("Failed to look up IDENTITY columns on [{}.{}]: {}", schema, tableName, metadataError.getMessage()); + } + } + + /** + * Computes the next value to seed an identity counter with: {@code MAX(col) + 1}. The caller only + * invokes this after at least one row has been inserted, so {@code MAX} is guaranteed non-null. + */ + private long computeNextValue(Connection connection, String schema, String tableName, String column) throws SQLException { + String sql = "SELECT MAX(" + quote(connection, column) + ") FROM " + qualifiedTable(connection, schema, tableName); + try (PreparedStatement ps = connection.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + long current = rs.getLong(1); + return rs.wasNull() ? 1L : current + 1L; + } + } + return 1L; + } + + /** + * Emits dialect-specific DDL to advance an identity counter past {@code next}. Unknown dialects are + * skipped with an info-level log — better than throwing and aborting the whole CSVIM cycle. + */ + private void executeIdentityRestart(DirigibleDataSource dataSource, Connection connection, String schema, String tableName, + String column, long next) throws SQLException { + String sql; + if (dataSource.isOfType(DatabaseSystem.H2)) { + sql = "ALTER TABLE " + qualifiedTable(connection, schema, tableName) + " ALTER COLUMN " + quote(connection, column) + + " RESTART WITH " + next; + } else if (dataSource.isOfType(DatabaseSystem.POSTGRESQL)) { + // setval(seq, n, false) -> next nextval() returns exactly n. + sql = "SELECT setval(pg_get_serial_sequence('" + schema + "." + tableName + "', '" + column + "'), " + next + ", false)"; + } else if (dataSource.isOfType(DatabaseSystem.MSSQL)) { + // RESEED stores the *current* identity, so the next assigned id is current + increment. + sql = "DBCC CHECKIDENT('" + schema + "." + tableName + "', RESEED, " + (next - 1) + ")"; + } else if (dataSource.isOfType(DatabaseSystem.MYSQL) || dataSource.isOfType(DatabaseSystem.MARIADB)) { + sql = "ALTER TABLE `" + schema + "`.`" + tableName + "` AUTO_INCREMENT = " + next; + } else { + logger.info("IDENTITY restart not implemented for dialect [{}] — skipping [{}.{}.{}]", dataSource.getDatabaseSystem(), schema, + tableName, column); + return; + } + try (PreparedStatement ps = connection.prepareStatement(sql)) { + ps.execute(); + } + } + + /** Returns the schema-qualified, dialect-quoted table identifier. */ + private static String qualifiedTable(Connection connection, String schema, String tableName) throws SQLException { + String q = connection.getMetaData() + .getIdentifierQuoteString(); + return q + schema + q + "." + q + tableName + q; + } + + /** Returns a dialect-quoted identifier. */ + private static String quote(Connection connection, String identifier) throws SQLException { + String q = connection.getMetaData() + .getIdentifierQuoteString(); + return q + identifier + q; + } + private boolean isDefaultDataSource(String dataSourceName) { return null == dataSourceName || dataSourceName.equalsIgnoreCase(defaultDataSourceName); } diff --git a/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/CsvimIdentityRestartIT.java b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/CsvimIdentityRestartIT.java new file mode 100644 index 00000000000..6775ad1e8e9 --- /dev/null +++ b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/CsvimIdentityRestartIT.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2010-2026 Eclipse Dirigible contributors + * + * All rights reserved. This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * SPDX-FileCopyrightText: Eclipse Dirigible contributors SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.dirigible.integration.tests.api; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.charset.StandardCharsets; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.List; + +import javax.sql.DataSource; + +import org.eclipse.dirigible.components.data.sources.manager.DataSourcesManager; +import org.eclipse.dirigible.components.initializers.synchronizer.SynchronizationProcessor; +import org.eclipse.dirigible.repository.api.IRepository; +import org.eclipse.dirigible.repository.api.IRepositoryStructure; +import org.eclipse.dirigible.tests.base.IntegrationTest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Verifies that {@code CsvimProcessor} advances a table's IDENTITY counter past the seeded explicit + * IDs. The seed CSV inserts rows with PKs 1..5; without the post-load restart, the IDENTITY counter + * would still point at 1 and the next "generate-me-one" INSERT would collide on PK = 1. + * + *

+ * Pure HTTP / JDBC — no Selenide, no IDE. + */ +class CsvimIdentityRestartIT extends IntegrationTest { + + private static final String PROJECT = "csvim-identity-restart-it"; + + private static final String TABLE_PATH = IRepositoryStructure.PATH_REGISTRY_PUBLIC + "/" + PROJECT + "/tables/book.table"; + private static final String CSV_PATH = IRepositoryStructure.PATH_REGISTRY_PUBLIC + "/" + PROJECT + "/data/books.csv"; + private static final String CSVIM_PATH = IRepositoryStructure.PATH_REGISTRY_PUBLIC + "/" + PROJECT + "/data/books.csvim"; + + private static final String TABLE_NAME = "CSVIM_IDENT_BOOK"; + + private static final String TABLE_SOURCE = """ + { + "name": "CSVIM_IDENT_BOOK", + "type": "TABLE", + "columns": [ + { + "type": "INTEGER", + "primaryKey": true, + "identity": true, + "nullable": false, + "name": "BOOK_ID" + }, + { + "type": "VARCHAR", + "length": 40, + "nullable": false, + "name": "BOOK_TITLE" + } + ] + } + """; + + private static final String CSV_SOURCE = """ + BOOK_ID,BOOK_TITLE + 1,Dune + 2,Foundation + 3,Neuromancer + 4,Hyperion + 5,Snow Crash + """; + + private static final String CSVIM_SOURCE = """ + { + "files": [ + { + "table": "CSVIM_IDENT_BOOK", + "schema": "PUBLIC", + "file": "/%s/data/books.csv", + "header": true, + "useHeaderNames": true, + "delimField": ",", + "distinguishEmptyFromNull": true, + "version": "1.0" + } + ] + } + """.formatted(PROJECT); + + @Autowired + private IRepository repository; + + @Autowired + private SynchronizationProcessor synchronizationProcessor; + + @Autowired + private DataSourcesManager dataSourcesManager; + + @Test + void identity_counter_is_advanced_past_explicitly_seeded_ids() throws Exception { + write(TABLE_PATH, TABLE_SOURCE); + write(CSV_PATH, CSV_SOURCE); + write(CSVIM_PATH, CSVIM_SOURCE); + synchronizationProcessor.forceProcessSynchronizers(); + + DataSource dataSource = dataSourcesManager.getDefaultDataSource(); + try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement()) { + + // Sanity: the 5 seeded rows are in place — MAX(BOOK_ID) == 5. + try (ResultSet rs = statement.executeQuery("SELECT MAX(\"BOOK_ID\") FROM \"" + TABLE_NAME + "\"")) { + assertThat(rs.next()).isTrue(); + assertThat(rs.getInt(1)).isEqualTo(5); + } + + // The actual contract: an INSERT that omits BOOK_ID must get id = 6 (not 1). + // If the IDENTITY counter wasn't advanced, this throws a PK-violation. + statement.execute("INSERT INTO \"" + TABLE_NAME + "\" (\"BOOK_TITLE\") VALUES ('Cryptonomicon')", + Statement.RETURN_GENERATED_KEYS); + try (ResultSet keys = statement.getGeneratedKeys()) { + assertThat(keys.next()).isTrue(); + assertThat(keys.getInt(1)).isEqualTo(6); + } + + // And MAX(BOOK_ID) now equals 6, confirming the row landed. + try (ResultSet rs = statement.executeQuery("SELECT MAX(\"BOOK_ID\") FROM \"" + TABLE_NAME + "\"")) { + assertThat(rs.next()).isTrue(); + assertThat(rs.getInt(1)).isEqualTo(6); + } + } + } + + private void write(String path, String source) { + repository.createResource(path, source.getBytes(StandardCharsets.UTF_8), false, "text/plain", true); + } + + @AfterEach + void cleanup() throws Exception { + for (String path : List.of(CSVIM_PATH, CSV_PATH, TABLE_PATH)) { + if (repository.hasResource(path)) { + repository.removeResource(path); + } + } + synchronizationProcessor.forceProcessSynchronizers(); + // Drop the table so reruns start from a clean state — the synchronizer's "keep data" policy + // means the table itself survives a .table file removal otherwise. + try (Connection connection = dataSourcesManager.getDefaultDataSource() + .getConnection(); + Statement statement = connection.createStatement()) { + statement.execute("DROP TABLE IF EXISTS \"" + TABLE_NAME + "\""); + } + } +}