I'm pretty sure our backend is mostly slowed by the many repository calls, which is just something we'll have to effectivise, but I haven't had luck implementing the Permissions solution you have.
We're running 3.3.0 EFCore, mysql, and I see no such folder as you describe. When adding them myself, I get:
Saying that the PermissionsManagementModal is missing, and that the .web part of Volo.Abp.PermissionManagement.Web.Pages.AbpPermissionManagement also is missing.
Here's our backend log when one of our calls are made: https://docs.google.com/document/d/1-hbP01lTpqIP3YVbyqlS7-C88OLmIwdMMzKYyGj-CQU/edit?usp=sharing
It's a call that fetches organizationUnits, but filtered for what organizations you are part of and all sub-orgs.
We do not use redis. What is it, and how could we?
We have tested it with both local frontend, backend and Db and deployed local, backend and Db, an a mixture of these. There is no seperate identity server, it all runs on two web services, and one azure MySql Db. The identity and tenant module is in the same Db as all of our entities.
We are 2 weeks from having to use this is a customer oriented version, so we would really appreciate any help.
Sorry for the late response, we are hard at work on a deadline.
It is because I want a dropdown that is sorted by organization (like the one on the organizations Page), so i run it through with a recursive method, which generates a orgList, with lists of objects inside them, for easily making a dropdown.
But here's the kicker: I suddenly realized that it works when I publish the API to Azure web app service and publish the frontend by gtihub to Azure web app service. So it may very well be a problem with some local packages or somesuch that I have, which the CI on github doesn't get.
Sooo... Closed? Sort of?
Sorry for the delayed response. The holidays and all.
In debug it shows the data as empty though, so I can't see how the html can impact it. Also the same html has worked with the endpoint that returns all organization units + children. Is it because I have placed the endpoint in another entity? - I don't see how it should affect it though + it still works on swagger. :/
Hah ha... Now don't laugh, but it was b/c i needed to import the module directly to app.module.ts, and restart the app, not just hot-reload :)
Hi armanozak, We're sort of deep into our development, so our angular directory alone is 700 mb, and we have several customizations on our program, such as, rabbitMq, microservices, custom identity entities and over 3-4 updates from 3.0.0 to 3.3.0, so honestly, it's a bit of a sizable jungle, and although I think the problem is in our frontend, but I agree not the component, it could also be from generating entities over several versions, where your Angular architecture changed considerably (which is my chief suspecion).
I'm not sure if I can share the project easily, but I've made a ticket out of it, if it helps.
Typescript:
import { TerminalMessageStatus } from '../../shared/enums/terminal-message-status';
import { ABP, ListService, PagedResultDto, TrackByService } from '@abp/ng.core';
import { Confirmation, ConfirmationService } from '@abp/ng.theme.shared';
import { DateAdapter } from '@abp/ng.theme.shared/extensions';
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
import { filter, finalize, switchMap, tap } from 'rxjs/operators';
import { TerminalCommands } from '../../store/models';
import { TerminalCommandsService } from './terminalCommands.service';
import { Observable, timer, Subscription, interval } from 'rxjs';
import { Router } from '@angular/router';
@Component({
selector: 'app-terminalCommands',
templateUrl: './terminalCommands.component.html',
styleUrls: ['./terminalCommands.component.scss'],
providers: [ListService, { provide: NgbDateAdapter, useClass: DateAdapter }],
})
export class TerminalCommandsComponent implements OnInit {
data: PagedResultDto<TerminalCommands.TerminalCommandWithNavigationProperties> = {
items: [],
totalCount: 0,
};
filters: Partial<TerminalCommands.TerminalCommandsQueryParams> = {};
form: FormGroup;
isFiltersHidden = true;
isModalBusy = false;
isModalOpen = false;
selected: TerminalCommands.TerminalCommandWithNavigationProperties;
terminalMessageTypeArr = Object.keys(TerminalMessageType).filter(value => isNaN(Number(value)) === false).map(key => ({ key: key, value: TerminalMessageType[key] }));
terminalMessageStatusArr = Object.keys(TerminalMessageStatus).filter(value => isNaN(Number(value)) === false).map(key => ({ key: key, value: TerminalMessageStatus[key] }));
constructor(
public readonly list: ListService,
public readonly track: TrackByService,
public readonly terminalCommandsService: TerminalCommandsService,
private confirmation: ConfirmationService,
private fb: FormBuilder,
private router: Router
) {}
ngOnInit() {
const getData = (query: ABP.PageQueryParams) =>
this.terminalCommandsService.getListByInput({
filterText: query.filter,
...query,
...this.filters,
});
const setData = (response: TerminalCommands.Response) => (this.data = response);
this.list.hookToQuery(getData).subscribe(setData);
this.start();
}
start(){
if(this.router.url == "/terminalCommands")
{
setTimeout(this.ngOnInit.bind(this),2000);
}
}
buildForm() {
this.form = this.fb.group({
productInstanceId: [(this.selected.productInstance || {}).id]
});
}
hideForm() {
this.isModalOpen = false;
this.form.reset();
}
showForm() {
/*
if(this.filters.productInstanceId == null){
return;
}*/
this.buildForm();
this.isModalOpen = true;
}
submitForm() {
if (this.form.invalid) return;
const request = this.selected.terminalCommand.id
? this.terminalCommandsService.updateByIdAndInput(this.form.value, this.selected.terminalCommand.id)
: this.terminalCommandsService.createByInput(this.form.value);
this.isModalBusy = true;
request
.pipe(
finalize(() => (this.isModalBusy = false)),
tap(() => this.hideForm()),
)
.subscribe(this.list.get);
}
create() {
this.selected = {
terminalCommand: {},
productInstance: {}
} as TerminalCommands.TerminalCommandWithNavigationProperties;
this.showForm();
}
update(record: TerminalCommands.TerminalCommandWithNavigationProperties) {
this.terminalCommandsService
.getByIdWithNavigationProperties(record.terminalCommand.id)
.subscribe((response: TerminalCommands.TerminalCommandWithNavigationProperties) => {
this.selected = response;
this.showForm();
});
}
delete(record: TerminalCommands.TerminalCommandWithNavigationProperties) {
this.confirmation.warn(
'::DeleteConfirmationMessage',
'::AreYouSure',
{ messageLocalizationParams: [] }
).pipe(
filter(status => status === Confirmation.Status.confirm),
switchMap(() => this.terminalCommandsService.deleteById(record.terminalCommand.id)),
).subscribe(this.list.get);
}
}
There's a method that keeps refreshing the data, and a lot of html removed, but other than that, it should be standard.
[1/4] Why do we have the module "@ng-bootstrap/ng-bootstrap"...? [2/4] Initialising dependency graph... warning @volo/abp.ng.identity > @abp/ng.components > ng-zorro-antd@9.3.0: please warning @angular-devkit/build-angular > webpack-dev-server > chokidar@2.1.8: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies. warning @angular-devkit/build-angular > webpack-dev-server > chokidar > fsevents@1.2.13: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2. warning @angular-devkit/build-angular > webpack > watchpack > watchpack-chokidar2 > chokidar@2.1.8: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies. warning @angular-devkit/build-angular > resolve-url-loader > rework > css > urix@0.1.0: Please see https://github.com/lydell/urix#deprecated warning @angular-devkit/build-angular > resolve-url-loader > rework > css > source-map-resolve > urix@0.1.0: Please see https://github.com/lydell/urix#deprecated warning @angular-devkit/build-angular > resolve-url-loader > rework > css > source-map-resolve > resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated warning @angular/cli > universal-analytics > request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142 warning @angular/cli > universal-analytics > request > har-validator@5.1.5: this library is no longer supported warning protractor > webdriver-manager > request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142 warning tslint@6.1.3: TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information. [3/4] Finding dependency... [4/4] Calculating file sizes... => Found "@ng-bootstrap/ng-bootstrap@7.0.0" info Reasons this module exists
Html:
<div class="col-auto">
<h1 class="content-header-title">{{ '::TerminalCommands' | abpLocalization}}</h1>
</div>
<div class="col-lg-auto pl-lg-0">
<abp-breadcrumb></abp-breadcrumb>
</div>
<div class="col">
<div class="text-lg-right pt-2">
<button
*abpPermission="'Stella.TerminalCommands.Create'"
class="btn btn-primary btn-sm"
type="button"
(click)="create()"
>
<i class="fa fa-plus mr-1"></i>
{{ '::NewTerminalCommand' | abpLocalization }}
</button>
</div>
</div>
</div>
<div class="card">
<div class="card-body">
<div class="col-12 col-sm-auto">
<div class="form-group">
<label>
{{ '::ProductInstance' | abpLocalization }}
</label>
<abp-lookup-input
[getFn]="terminalCommandsService.productInstanceLookup"
[ngModelOptions]="{ standalone: true }"
displayNameProp="stellaId"
lookupNameProp="displayName"
[(ngModel)]="filters.productInstanceId"
></abp-lookup-input>
</div>
</div>
<ngx-datatable [rows]="data.items" [count]="data.totalCount" [list]="list" default>
<ngx-datatable-column name="{{ '::IsIncoming' | abpLocalization }}" prop="terminalCommand.isIncoming">
<ng-template let-row="row" ngx-datatable-cell-template>
<ng-template [ngIf]="row.terminalCommand?.isIncoming" [ngIfThen]="yes" [ngIfElse]="no"></ng-template>
<ng-template #yes>
<div class="text-center text-success">
<i [title]="'AbpUi::Yes' | abpLocalization" class="fa fa-check"></i>
</div>
</ng-template>
<ng-template #no>
<div class="text-center text-danger">
<i [title]="'AbpUi::No' | abpLocalization" class="fa fa-times"></i>
</div>
</ng-template>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="{{ '::Source' | abpLocalization }}" prop="terminalCommand.source">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ '::Enum:TerminalMessageType:' + row.terminalCommand?.source | abpLocalization }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="{{ '::Status' | abpLocalization }}" prop="terminalCommand.status">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ '::Enum:TerminalMessageStatus:' + row.terminalCommand?.status | abpLocalization }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="{{ '::ErrorMessage' | abpLocalization }}" prop="terminalCommand.errorMessage">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.terminalCommand?.errorMessage }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="{{ '::CommandText' | abpLocalization }}" prop="terminalCommand.commandText">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.terminalCommand?.commandText }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="{{ '::ProductInstance' | abpLocalization }}" prop="productInstance.stellaId">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.productInstance?.stellaId }}
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
<abp-modal [busy]="isModalBusy" [(visible)]="isModalOpen">
<ng-template #abpHeader>
<h3>{{ (selected?.terminalCommand.id ? 'AbpUi::Edit' : '::NewTerminalCommand') | abpLocalization }}</h3>
</ng-template>
<ng-template #abpBody>
<form [formGroup]="form" (ngSubmit)="submitForm()" validateOnSubmit>
<div class="mt-2 fade-in-top">
<div class="form-group">
<label for="terminalCommand-source">
{{ '::Source' | abpLocalization }}
</label>
<select
id="terminalCommand-source"
formControlName="source"
class="custom-select form-control"
>
<option *ngFor="let x of terminalMessageTypeArr; trackBy: track.by('key')" [ngValue]="x.key">
{{ '::Enum:TerminalMessageType:' + x.key | abpLocalization }}
</option>
</select>
</div>
<div class="form-group">
<label for="terminalCommand-commandText">
{{ '::CommandText' | abpLocalization }}
</label>
<input
type="text"
id="terminalCommand-commandText"
formControlName="commandText"
class="form-control"/>
</div>
<div class="form-group">
<label for="ProductInstance-StellaId">
{{ '::ProductInstance' | abpLocalization }}
</label>
<abp-lookup-input
[getFn]="terminalCommandsService.productInstanceLookup"
[editingData]="selected.productInstance"
displayNameProp="stellaId"
lookupNameProp="displayName"
formControlName="productInstanceId">
</abp-lookup-input>
</div>
</div>
</form>
</ng-template>
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" #abpClose>
{{ 'AbpUi::Cancel' | abpLocalization }}
</button>
<abp-button
iconClass="fa fa-check"
(click)="submitForm()"
[disabled]="form?.invalid"
>
{{ 'AbpUi::Save' | abpLocalization }}
</abp-button>
</ng-template>
</abp-modal>