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 +}