diff --git a/generators/angular/__snapshots__/generator.spec.ts.snap b/generators/angular/__snapshots__/generator.spec.ts.snap
index 58584359f100..293ef39c541e 100644
--- a/generators/angular/__snapshots__/generator.spec.ts.snap
+++ b/generators/angular/__snapshots__/generator.spec.ts.snap
@@ -3307,6 +3307,69 @@ exports[`generator - angular monolith-jwt-skipUserManagement(false)-withAdminUi(
"src/main/webapp/app/core/util/parse-links.service.ts": {
"stateCleared": "modified",
},
+ "src/main/webapp/app/entities/authority/authority.model.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/authority.routes.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/authority.test-samples.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/delete/authority-delete-dialog.component.html": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/delete/authority-delete-dialog.component.spec.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/delete/authority-delete-dialog.component.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/detail/authority-detail.component.html": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/detail/authority-detail.component.spec.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/detail/authority-detail.component.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/list/authority.component.html": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/list/authority.component.spec.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/list/authority.component.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/route/authority-routing-resolve.service.spec.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/route/authority-routing-resolve.service.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/service/authority.service.spec.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/service/authority.service.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/update/authority-form.service.spec.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/update/authority-form.service.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/update/authority-update.component.html": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/update/authority-update.component.spec.ts": {
+ "stateCleared": "modified",
+ },
+ "src/main/webapp/app/entities/authority/update/authority-update.component.ts": {
+ "stateCleared": "modified",
+ },
"src/main/webapp/app/entities/entity-navbar-items.ts": {
"stateCleared": "modified",
},
diff --git a/generators/angular/entity-files-angular.ts b/generators/angular/entity-files-angular.ts
index aea4032fab00..e2e87392c1ce 100644
--- a/generators/angular/entity-files-angular.ts
+++ b/generators/angular/entity-files-angular.ts
@@ -75,12 +75,7 @@ export const angularFiles = {
export async function writeEntitiesFiles(this: CoreGenerator, { application, entities }: GeneratorDefinition['writingEntitiesTaskParam']) {
for (const entity of entities.filter(entity => !entity.skipClient)) {
- if (!entity.builtIn) {
- await this.writeFiles({
- sections: angularFiles,
- context: { ...application, ...entity },
- });
- } else if (entity.builtInUser) {
+ if (entity.builtInUser) {
await this.writeFiles({
sections: builtInFiles,
context: {
@@ -90,13 +85,18 @@ export async function writeEntitiesFiles(this: CoreGenerator, { application, ent
readOnly: true,
},
});
+ } else {
+ await this.writeFiles({
+ sections: angularFiles,
+ context: { ...application, ...entity },
+ });
}
}
}
export async function postWriteEntitiesFiles(this: CoreGenerator, taskParam: GeneratorDefinition['postWritingEntitiesTaskParam']) {
const { source, application } = taskParam;
- const entities = taskParam.entities.filter(entity => !entity.skipClient && !entity.builtIn && !entity.embedded);
+ const entities = taskParam.entities.filter(entity => !entity.skipClient && !entity.builtInUser && !entity.embedded);
source.addEntitiesToClient({ application, entities });
}
diff --git a/generators/angular/generator.ts b/generators/angular/generator.ts
index 65823299b10d..9ee2fa8d87c9 100644
--- a/generators/angular/generator.ts
+++ b/generators/angular/generator.ts
@@ -46,7 +46,7 @@ import {
generateTypescriptTestEntity as generateTestEntity,
} from '../client/support/index.js';
import type { CommonClientServerApplication } from '../base-application/types.js';
-import { createNeedleCallback } from '../base/support/index.js';
+import { createNeedleCallback, mutateData } from '../base/support/index.js';
const { ANGULAR } = clientFrameworkTypes;
@@ -141,6 +141,25 @@ export default class AngularGenerator extends BaseApplicationGenerator {
return this.asPreparingTaskGroup(this.delegateTasksToBlueprint(() => this.preparing));
}
+ get preparingEachEntity() {
+ return this.asPreparingEachEntityTaskGroup({
+ prepareEntity({ entity }) {
+ const asAuthorities = authorities => (authorities.length > 0 ? authorities.map(auth => `'${auth}'`).join(', ') : undefined);
+ mutateData(entity, {
+ entityAngularAuthorities: asAuthorities(entity.entityAuthority?.split(',') ?? []),
+ entityAngularReadAuthorities: asAuthorities([
+ ...(entity.entityAuthority?.split(',') ?? []),
+ ...(entity.entityReadAuthority?.split(',') ?? []),
+ ]),
+ });
+ },
+ });
+ }
+
+ get [BaseApplicationGenerator.PREPARING_EACH_ENTITY]() {
+ return this.delegateTasksToBlueprint(() => this.preparingEachEntity);
+ }
+
get default() {
return this.asDefaultTaskGroup({
loadEntities() {
diff --git a/generators/angular/support/needles.ts b/generators/angular/support/needles.ts
index 1a5bc7c80e71..1b7138f4af6f 100644
--- a/generators/angular/support/needles.ts
+++ b/generators/angular/support/needles.ts
@@ -100,6 +100,7 @@ export function addItemToMenu({
${name}
`;
+
return createNeedleCallback({
needle,
contentToAdd,
@@ -130,22 +131,14 @@ export function addToEntitiesMenu({ application, entities }: { application: Base
const { enableTranslation, jhiPrefix } = application;
return joinCallbacks(
...entities.map(entity => {
- const { entityPage, entityTranslationKeyMenu, entityClassHumanized } = entity;
- const routerLink = `routerLink="/${entityPage}"`;
-
- // prettier-ignore
- const contentToAdd =`
-
-
-
- ${entityClassHumanized}
-
- `;
-
- return createNeedleCallback({
- needle: 'jhipster-needle-add-entity-to-menu',
- contentToAdd,
- contentToCheck: routerLink,
+ return addItemToMenu({
+ needle: entity.adminEntity ? 'jhipster-needle-add-element-to-admin-menu' : 'jhipster-needle-add-entity-to-menu',
+ enableTranslation,
+ icon: 'asterisk',
+ route: entity.entityPage,
+ translationKey: `global.menu.entities.${entity.entityTranslationKeyMenu}`,
+ name: entity.entityClassHumanized,
+ jhiPrefix,
});
}),
);
diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.routes.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.routes.ts.ejs
index 3611f1d5952c..692c8f3b7965 100644
--- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.routes.ts.ejs
+++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/_entityFile_.routes.ts.ejs
@@ -33,6 +33,9 @@ const <%= entityInstance %>Route: Routes = [
component: <%= entityAngularName %>Component,
data: {
defaultSort: '<%- primaryKey.name %>,' + ASC,
+<%_ if (entityAngularReadAuthorities) { _%>
+ authorities: [<%- entityAngularReadAuthorities %>],
+<%_ } _%>
},
canActivate: [UserRouteAccessService]
},
@@ -42,6 +45,11 @@ const <%= entityInstance %>Route: Routes = [
resolve: {
<%= entityInstance %>: <%= entityAngularName %>Resolve
},
+<%_ if (entityAngularReadAuthorities) { _%>
+ data: {
+ authorities: [<%- entityAngularReadAuthorities %>],
+ },
+<%_ } _%>
canActivate: [UserRouteAccessService]
},
<%_ if (!readOnly) { _%>
@@ -51,6 +59,11 @@ const <%= entityInstance %>Route: Routes = [
resolve: {
<%= entityInstance %>: <%= entityAngularName %>Resolve
},
+<%_ if (entityAngularAuthorities) { _%>
+ data: {
+ authorities: [<%- entityAngularAuthorities %>],
+ },
+<%_ } _%>
canActivate: [UserRouteAccessService]
},
<%_ } _%>
@@ -61,6 +74,11 @@ const <%= entityInstance %>Route: Routes = [
resolve: {
<%= entityInstance %>: <%= entityAngularName %>Resolve
},
+<%_ if (entityAngularAuthorities) { _%>
+ data: {
+ authorities: [<%- entityAngularAuthorities %>],
+ },
+<%_ } _%>
canActivate: [UserRouteAccessService]
},
<%_ } _%>
diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-form.service.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-form.service.spec.ts.ejs
index e210e9667c1e..d331d83e8371 100644
--- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-form.service.spec.ts.ejs
+++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-form.service.spec.ts.ejs
@@ -86,6 +86,7 @@ describe('<%= entityAngularName %> Form Service', () => {
expect(<%= entityInstance %>).toMatchObject(sampleWithRequiredData);
});
});
+<%_ if (primaryKey.autoGenerate) { _%>
describe('resetForm', () => {
it('passing I<%= entityAngularName %> should not enable <%= primaryKey.name %> FormControl', () => {
@@ -106,5 +107,6 @@ describe('<%= entityAngularName %> Form Service', () => {
expect(formGroup.controls.<%= primaryKey.name %>.disabled).toBe(true);
});
});
+<%_ } _%>
});
});
diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs
index 906fbfe236f7..5bd190ced693 100644
--- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs
+++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.html.ejs
@@ -101,7 +101,7 @@ _%>
data-cy="<%= fieldName %>" formControlName="<%= fieldName %>" <% if (readonly) { %> [readonly]="true"<% } %>/>
<%_ } else { _%>
[readonly]="editForm.get('<%= primaryKey.name %>')!.value != null"<% } else if (readonly) { %> [readonly]="true"<% } %>/>
+ formControlName="<%= fieldName %>"<% if (field.id && !field.autoGenerate) { %> [readonly]="editForm.get('<%= primaryKey.name %>')!.disabled"<% } else if (readonly) { %> [readonly]="true"<% } %>/>
<%_ if (field.fieldTypeBinary && !field.blobContentTypeText) { _%>
diff --git a/generators/base-application/types/entity.d.ts b/generators/base-application/types/entity.d.ts
index 6e2479b45e20..e441a6305c33 100644
--- a/generators/base-application/types/entity.d.ts
+++ b/generators/base-application/types/entity.d.ts
@@ -36,8 +36,14 @@ export type BaseEntity = {
skipServer?: boolean;
};
+type AngularEntity = {
+ entityAngularAuthorities?: string;
+ entityAngularReadAuthorities?: string;
+};
+
type Entity = Required &
- SpringEntity & {
+ SpringEntity &
+ AngularEntity & {
builtIn?: boolean;
builtInUser?: boolean;
builtInAuthority?: boolean;
diff --git a/generators/bootstrap-application-base/utils.js b/generators/bootstrap-application-base/utils.js
index cfaaf2d98b02..8a0532a871b7 100644
--- a/generators/bootstrap-application-base/utils.js
+++ b/generators/bootstrap-application-base/utils.js
@@ -125,7 +125,7 @@ export function createAuthorityEntity(customAuthorityData = {}, application) {
relationships: [],
fields: entityDefinition ? entityDefinition.fields || [] : [],
builtInAuthority: true,
- skipClient: true,
+ skipClient: !application.backendTypeSpringBoot || application.clientFrameworkReact || application.clientFrameworkVue,
searchEngine: 'no',
service: 'no',
dto: 'no',
diff --git a/generators/client/generator.js b/generators/client/generator.js
index 0e8086cd36c6..8a6e870dff61 100644
--- a/generators/client/generator.js
+++ b/generators/client/generator.js
@@ -236,7 +236,7 @@ export default class JHipsterClientGenerator extends BaseApplicationGenerator {
if (!application.webappEnumerationsDir || ![ANGULAR, VUE, REACT].includes(application.clientFramework)) {
return;
}
- for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtIn)) {
+ for (const entity of entities.filter(entity => !entity.skipClient)) {
await addEnumerationFiles.call(this, { application, entity });
}
},
diff --git a/generators/cypress/__snapshots__/generator.spec.ts.snap b/generators/cypress/__snapshots__/generator.spec.ts.snap
index b85bd546133d..f19b4e1082c0 100644
--- a/generators/cypress/__snapshots__/generator.spec.ts.snap
+++ b/generators/cypress/__snapshots__/generator.spec.ts.snap
@@ -35,6 +35,9 @@ exports[`generator - cypress jwt-cypressAudit(false)-angular-withAdminUi(false)-
"clientRoot/src/test/javascript/cypress/e2e/administration/administration.cy.ts": {
"stateCleared": "modified",
},
+ "clientRoot/src/test/javascript/cypress/e2e/entity/authority.cy.ts": {
+ "stateCleared": "modified",
+ },
"clientRoot/src/test/javascript/cypress/e2e/entity/entity-a.cy.ts": {
"stateCleared": "modified",
},
@@ -366,6 +369,9 @@ exports[`generator - cypress session-cypressAudit(false)-angular-withAdminUi(fal
"src/test/javascript/cypress/e2e/administration/administration.cy.ts": {
"stateCleared": "modified",
},
+ "src/test/javascript/cypress/e2e/entity/authority.cy.ts": {
+ "stateCleared": "modified",
+ },
"src/test/javascript/cypress/e2e/entity/entity-a.cy.ts": {
"stateCleared": "modified",
},
diff --git a/generators/cypress/files.ts b/generators/cypress/files.ts
index 3350c43d4f15..afa10e47be43 100644
--- a/generators/cypress/files.ts
+++ b/generators/cypress/files.ts
@@ -103,7 +103,6 @@ export const cypressFiles: WriteFileSection = {
testsCypress: [
{
- condition: ctx => !ctx.builtIn && !ctx.embedded,
path: CYPRESS_TEMPLATE_SOURCE_DIR,
renameTo: ctx => `${ctx.cypressDir}e2e/entity/${ctx.entityFileName}.cy.ts`,
templates: ['e2e/entity/_entity_.cy.ts'],
diff --git a/generators/cypress/generator.ts b/generators/cypress/generator.ts
index 2e5f3a5c6ed8..539d7f7e4775 100644
--- a/generators/cypress/generator.ts
+++ b/generators/cypress/generator.ts
@@ -160,7 +160,7 @@ export default class CypressGenerator extends BaseApplicationGenerator {
},
async writeCypressEntityFiles({ application, entities }) {
- for (const entity of entities) {
+ for (const entity of entities.filter(entity => !entity.skipClient && !entity.embedded && !entity.builtInUser)) {
const context = { ...application, ...entity } as any;
await this.writeFiles({
sections: cypressEntityFiles,
diff --git a/generators/cypress/templates/src/test/javascript/cypress/e2e/entity/_entity_.cy.ts.ejs b/generators/cypress/templates/src/test/javascript/cypress/e2e/entity/_entity_.cy.ts.ejs
index 6d361a04b4b8..8e126b5db1bb 100644
--- a/generators/cypress/templates/src/test/javascript/cypress/e2e/entity/_entity_.cy.ts.ejs
+++ b/generators/cypress/templates/src/test/javascript/cypress/e2e/entity/_entity_.cy.ts.ejs
@@ -50,8 +50,8 @@ describe('<%= entityClass %> e2e test', () => {
const <%= entityInstance %>PageUrl = '/<%= entityPage %>';
const <%= entityInstance %>PageUrlPattern = new RegExp('/<%= entityPage %>(\\?.*)?$');
- const username = Cypress.env('E2E_USERNAME') ?? 'user';
- const password = Cypress.env('E2E_PASSWORD') ?? 'user';
+ const username = Cypress.env('E2E_USERNAME') ?? '<%- adminEntity ? 'admin' : 'user' %>';
+ const password = Cypress.env('E2E_PASSWORD') ?? '<%- adminEntity ? 'admin' : 'user' %>';
<% if (skipCreateTest) { %>// <% } %>const <%= entityInstance %>Sample = <%- JSON.stringify(this.generateTestEntity(sampleFields.map(field => field.reference))) %>;
let <%= entityInstance %>;
diff --git a/generators/languages/entity-files.js b/generators/languages/entity-files.js
index b7cfd185be40..a88aa498e073 100644
--- a/generators/languages/entity-files.js
+++ b/generators/languages/entity-files.js
@@ -52,7 +52,7 @@ export function writeEntityFiles() {
return {
async writeEnumFiles({ entities, application }) {
if (!application.enableTranslation || application.skipClient) return;
- entities = entities.filter(entity => !entity.skipClient && !entity.builtIn);
+ entities = entities.filter(entity => !entity.skipClient && !entity.builtInUser);
const { clientSrcDir, packageName, frontendAppName } = application;
await Promise.all(
entities
@@ -81,7 +81,7 @@ export function writeEntityFiles() {
async writeClientFiles({ application, entities }) {
if (application.skipClient) return;
- const entitiesToWriteTranslationFor = entities.filter(entity => !entity.skipClient && !entity.builtIn);
+ const entitiesToWriteTranslationFor = entities.filter(entity => !entity.skipClient && !entity.builtInUser);
// Copy each
const { clientSrcDir, frontendAppName } = application;
diff --git a/generators/languages/generator.js b/generators/languages/generator.js
index 9dc36927b7b8..a8ff5c1bb73e 100644
--- a/generators/languages/generator.js
+++ b/generators/languages/generator.js
@@ -370,7 +370,7 @@ export default class LanguagesGenerator extends BaseApplicationGenerator {
addEntities({ application, entities, source }) {
if (application.skipClient) return;
const languagesToApply = application.enableTranslation ? this.languagesToApply : [...new Set([application.nativeLanguage, 'en'])];
- for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtIn)) {
+ for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtInUser)) {
for (const language of languagesToApply) {
source.addEntityTranslationKey?.({
language,
diff --git a/generators/react/entity-files-react.js b/generators/react/entity-files-react.js
index 80284ddafaa2..04a2bbc8c0f0 100644
--- a/generators/react/entity-files-react.js
+++ b/generators/react/entity-files-react.js
@@ -51,7 +51,7 @@ export const reactFiles = {
};
export async function writeEntitiesFiles({ application, entities }) {
- for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtIn)) {
+ for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtInUser)) {
await this.writeFiles({
sections: reactFiles,
context: { ...application, ...entity },
@@ -60,7 +60,7 @@ export async function writeEntitiesFiles({ application, entities }) {
}
export async function postWriteEntitiesFiles({ application, entities }) {
- for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtIn)) {
+ for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtInUser)) {
if (!entity.embedded) {
const { entityInstance, entityClass, entityAngularName, entityFolderName, entityFileName } = entity;
@@ -75,7 +75,7 @@ export async function postWriteEntitiesFiles({ application, entities }) {
}
export function cleanupEntitiesFiles({ application, entities }) {
- for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtIn)) {
+ for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtInUser)) {
const { entityFolderName, entityFileName } = entity;
if (this.isJhipsterVersionLessThan('7.0.0-beta.1')) {
diff --git a/generators/vue/entity-files-vue.js b/generators/vue/entity-files-vue.js
index e15601b53f7b..750c2f3dbbf4 100644
--- a/generators/vue/entity-files-vue.js
+++ b/generators/vue/entity-files-vue.js
@@ -51,7 +51,7 @@ export const entityFiles = {
};
export async function writeEntityFiles({ application, entities }) {
- for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtIn)) {
+ for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtInUser)) {
await this.writeFiles({
sections: entityFiles,
context: { ...application, ...entity },
@@ -60,7 +60,7 @@ export async function writeEntityFiles({ application, entities }) {
}
export async function postWriteEntityFiles({ application, entities }) {
- for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtIn)) {
+ for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtInUser)) {
if (!entity.embedded) {
const { enableTranslation } = application;
const {
@@ -94,7 +94,7 @@ export async function postWriteEntityFiles({ application, entities }) {
}
export function cleanupEntitiesFiles({ application, entities }) {
- for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtIn)) {
+ for (const entity of entities.filter(entity => !entity.skipClient && !entity.builtInUser)) {
const { entityFolderName, entityFileName } = entity;
if (this.isJhipsterVersionLessThan('8.0.0-beta.3')) {
this.removeFile(`${application.clientTestDir}/spec/app/entities/${entityFolderName}/${entityFileName}.component.spec.ts`);
diff --git a/generators/vue/files-vue.js b/generators/vue/files-vue.js
index 06d221f00b02..a2e93da71939 100644
--- a/generators/vue/files-vue.js
+++ b/generators/vue/files-vue.js
@@ -302,7 +302,7 @@ export async function writeFiles({ application }) {
}
export async function writeEntitiesFiles({ application, entities }) {
- entities = entities.filter(entity => !entity.skipClient && !entity.builtIn);
+ entities = entities.filter(entity => !entity.skipClient && !entity.builtInUser);
await this.writeFiles({
sections: entitiesFiles,
context: {
diff --git a/test-integration/samples/jdl-entities/02-authority-relationship.jdl b/test-integration/samples/jdl-entities/02-authority-relationship.jdl
new file mode 100644
index 000000000000..64f1eccf1f3a
--- /dev/null
+++ b/test-integration/samples/jdl-entities/02-authority-relationship.jdl
@@ -0,0 +1,11 @@
+@ChangelogDate(20230200000000)
+entity AuthorityRelationship {
+ name String
+}
+
+@EntityReadAuthority(ROLE_USER)
+entity Authority {}
+
+relationship ManyToOne {
+ AuthorityRelationship{authority} to Authority
+}