Browse Source

Merge pull request #24579 from abpframework/issue-24564

Angular - Applying the latest migrations - Issue 24564
issue-24672
Fahri Gedik 8 months ago
committed by GitHub
parent
commit
bdd621b6bd
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 78
      npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.html
  2. 23
      npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts
  3. 240
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form-prop.component.html
  4. 7
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form-prop.component.ts
  5. 65
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form.component.html
  6. 4
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form.component.ts
  7. 4
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html
  8. 103
      npm/ng-packs/packages/components/extensible/src/lib/components/grid-actions/grid-actions.component.html
  9. 13
      npm/ng-packs/packages/components/extensible/src/lib/components/grid-actions/grid-actions.component.ts
  10. 26
      npm/ng-packs/packages/components/extensible/src/lib/components/page-toolbar/page-toolbar.component.html
  11. 8
      npm/ng-packs/packages/components/extensible/src/lib/components/page-toolbar/page-toolbar.component.ts
  12. 4
      npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.ts
  13. 218
      npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.html
  14. 3
      npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts
  15. 7
      npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.ts
  16. 36
      npm/ng-packs/packages/theme-basic/src/lib/components/page-alert-container/page-alert-container.component.html
  17. 4
      npm/ng-packs/packages/theme-basic/src/lib/components/page-alert-container/page-alert-container.component.ts
  18. 102
      npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.html
  19. 3
      npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts
  20. 7
      npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts
  21. 4
      npm/ng-packs/packages/theme-shared/src/lib/components/card/card-body.component.ts
  22. 5
      npm/ng-packs/packages/theme-shared/src/lib/components/card/card-footer.component.ts
  23. 5
      npm/ng-packs/packages/theme-shared/src/lib/components/card/card-header.component.ts
  24. 5
      npm/ng-packs/packages/theme-shared/src/lib/components/card/card.component.ts
  25. 13
      npm/ng-packs/packages/theme-shared/src/lib/components/checkbox/checkbox.component.ts
  26. 77
      npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.html
  27. 4
      npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts
  28. 13
      npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts
  29. 4
      npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.ts
  30. 7
      npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts
  31. 2
      npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.html
  32. 4
      npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.ts
  33. 18
      npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.html
  34. 3
      npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.ts
  35. 74
      templates/app-nolayers/angular/src/app/home/home.component.html
  36. 74
      templates/app/angular/src/app/home/home.component.html

78
npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.html

@ -5,61 +5,47 @@
<div class="col-12 col-md-3">
<ul class="nav flex-column nav-pills" id="nav-tab" role="tablist">
@if (!hideChangePasswordTab && (profile$ | async)) {
<li class="nav-item" (click)="selectedTab = 0">
<a
class="nav-link"
[ngClass]="{ active: selectedTab === 0 }"
role="tab"
href="javascript:void(0)"
>{{ 'AbpUi::ChangePassword' | abpLocalization }}</a
>
</li>
<li class="nav-item" (click)="selectedTab = 0">
<a class="nav-link" [class.active]="selectedTab === 0" role="tab" href="javascript:void(0)">{{
'AbpUi::ChangePassword' | abpLocalization }}</a>
</li>
}
<li class="nav-item mb-2" (click)="selectedTab = 1">
<a
class="nav-link"
[ngClass]="{ active: selectedTab === 1 }"
role="tab"
href="javascript:void(0)"
>{{ 'AbpAccount::PersonalSettings' | abpLocalization }}</a
>
<a class="nav-link" [class.active]="selectedTab === 1" role="tab" href="javascript:void(0)">{{
'AbpAccount::PersonalSettings' | abpLocalization }}</a>
</li>
</ul>
</div>
@if (profile$ | async) {
<div class="col-12 col-md-9">
@if (selectedTab === 0) {
<div class="tab-content" [@fadeIn]>
<div class="tab-pane active" role="tabpanel">
<h4>
{{ 'AbpIdentity::ChangePassword' | abpLocalization }}
<hr />
</h4>
<abp-change-password-form
*abpReplaceableTemplate="{
<div class="col-12 col-md-9">
@if (selectedTab === 0) {
<div class="tab-content fade-in">
<div class="tab-pane active" role="tabpanel">
<h4>
{{ 'AbpIdentity::ChangePassword' | abpLocalization }}
<hr />
</h4>
<abp-change-password-form *abpReplaceableTemplate="{
componentKey: changePasswordKey
}"
></abp-change-password-form>
</div>
</div>
}
@if (selectedTab === 1) {
<div class="tab-content" [@fadeIn]>
<div class="tab-pane active" role="tabpanel">
<h4>
{{ 'AbpIdentity::PersonalSettings' | abpLocalization }}
<hr />
</h4>
<abp-personal-settings-form
*abpReplaceableTemplate="{
}"></abp-change-password-form>
</div>
</div>
}
@if (selectedTab === 1) {
<div class="tab-content fade-in">
<div class="tab-pane active" role="tabpanel">
<h4>
{{ 'AbpIdentity::PersonalSettings' | abpLocalization }}
<hr />
</h4>
<abp-personal-settings-form *abpReplaceableTemplate="{
componentKey: personalSettingsKey
}"
></abp-personal-settings-form>
</div>
</div>
}
}"></abp-personal-settings-form>
</div>
</div>
}
</div>
}
</div>
</div>
</div>
</div>

23
npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts

@ -1,10 +1,9 @@
import { ProfileService } from '@abp/ng.account.core/proxy';
import { fadeIn, LoadingDirective } from '@abp/ng.theme.shared';
import { transition, trigger, useAnimation } from '@angular/animations';
import { LoadingDirective } from '@abp/ng.theme.shared';
import { Component, inject, OnInit } from '@angular/core';
import { eAccountComponents } from '../../enums/components';
import { ManageProfileStateService } from '../../services/manage-profile.state.service';
import { NgClass, AsyncPipe } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { LocalizationPipe, ReplaceableTemplateDirective } from '@abp/ng.core';
import { PersonalSettingsComponent } from '../personal-settings/personal-settings.component';
@ -13,24 +12,34 @@ import { ChangePasswordComponent } from '../change-password/change-password.comp
@Component({
selector: 'abp-manage-profile',
templateUrl: './manage-profile.component.html',
animations: [trigger('fadeIn', [transition(':enter', useAnimation(fadeIn))])],
styles: [
//TODO: move static styles
`
.min-h-400 {
min-height: 400px;
}
.fade-in {
animation: fadeIn 350ms ease both;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
`,
],
imports: [
NgClass,
AsyncPipe,
ReactiveFormsModule,
PersonalSettingsComponent,
ChangePasswordComponent,
LocalizationPipe,
ReplaceableTemplateDirective,
LoadingDirective,
LoadingDirective
],
})
export class ManageProfileComponent implements OnInit {

240
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form-prop.component.html

@ -1,177 +1,113 @@
<ng-container *abpPermission="prop.permission; runChangeDetection: false">
@switch (getComponent(prop)) {
@case ('template') {
<ng-container *ngComponentOutlet="prop.template; injector: injectorForCustomComponent" />
}
@case ('template') {
<ng-container *ngComponentOutlet="prop.template; injector: injectorForCustomComponent" />
}
}
<div [ngClass]="containerClassName" class="mb-2">
<div [class]="containerClassName" class="mb-2">
@switch (getComponent(prop)) {
@case ('input') {
<ng-template [ngTemplateOutlet]="label" />
<input
#field
[id]="prop.id"
[formControlName]="prop.name"
[autocomplete]="prop.autocomplete"
[type]="getType(prop)"
[abpDisabled]="disabled"
[readonly]="readonly"
class="form-control"
/>
}
@case ('hidden') {
<input [formControlName]="prop.name" type="hidden" />
}
@case ('checkbox') {
<div class="form-check" validationTarget>
<input
#field
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="disabled"
type="checkbox"
class="form-check-input"
/>
<ng-template
[ngTemplateOutlet]="label"
[ngTemplateOutletContext]="{ $implicit: 'form-check-label' }"
/>
</div>
}
@case ('select') {
<ng-template [ngTemplateOutlet]="label" />
<select
#field
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="disabled"
class="form-select form-control"
>
@for (option of options$ | async; track option.value) {
<option [ngValue]="option.value">
@if (prop.isExtra) {
{{ '::' + option.key | abpLocalization }}
} @else {
{{ option.key }}
}
</option>
}
</select>
}
@case ('multiselect') {
<ng-template [ngTemplateOutlet]="label"></ng-template>
<abp-extensible-form-multi-select
[prop]="prop"
[options]="options$ | async"
[formControlName]="prop.name"
[abpDisabled]="disabled"
/>
}
@case ('typeahead') {
<ng-template [ngTemplateOutlet]="label" />
<div #typeahead class="position-relative" validationStyle validationTarget>
<input
#field
[id]="prop.id"
[autocomplete]="prop.autocomplete"
[abpDisabled]="disabled"
[ngbTypeahead]="search"
[editable]="false"
[inputFormatter]="typeaheadFormatter"
[resultFormatter]="typeaheadFormatter"
[ngModelOptions]="{ standalone: true }"
[(ngModel)]="typeaheadModel"
(selectItem)="setTypeaheadValue($event.item)"
(blur)="setTypeaheadValue(typeaheadModel)"
[class.is-invalid]="typeahead.classList.contains('is-invalid')"
class="form-control"
/>
<input [formControlName]="prop.name" type="hidden" />
</div>
}
@case ('date') {
<ng-template [ngTemplateOutlet]="label" />
<input
[id]="prop.id"
[formControlName]="prop.name"
(click)="datepicker.open()"
(keyup.space)="datepicker.open()"
ngbDatepicker
#datepicker="ngbDatepicker"
type="text"
class="form-control"
/>
}
@case ('time') {
<ng-template [ngTemplateOutlet]="label" />
<ngb-timepicker [formControlName]="prop.name" />
}
@case ('dateTime') {
<ng-template [ngTemplateOutlet]="label" />
<abp-extensible-date-time-picker [prop]="prop" [meridian]="meridian$ | async" />
}
@case ('textarea') {
<ng-template [ngTemplateOutlet]="label" />
<textarea
#field
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="disabled"
[readonly]="readonly"
class="form-control"
></textarea>
@case ('input') {
<ng-template [ngTemplateOutlet]="label" />
<input #field [id]="prop.id" [formControlName]="prop.name" [autocomplete]="prop.autocomplete" [type]="getType(prop)"
[abpDisabled]="disabled" [readonly]="readonly" class="form-control" />
}
@case ('hidden') {
<input [formControlName]="prop.name" type="hidden" />
}
@case ('checkbox') {
<div class="form-check" validationTarget>
<input #field [id]="prop.id" [formControlName]="prop.name" [abpDisabled]="disabled" type="checkbox"
class="form-check-input" />
<ng-template [ngTemplateOutlet]="label" [ngTemplateOutletContext]="{ $implicit: 'form-check-label' }" />
</div>
}
@case ('select') {
<ng-template [ngTemplateOutlet]="label" />
<select #field [id]="prop.id" [formControlName]="prop.name" [abpDisabled]="disabled"
class="form-select form-control">
@for (option of options$ | async; track option.value) {
<option [ngValue]="option.value">
@if (prop.isExtra) {
{{ '::' + option.key | abpLocalization }}
} @else {
{{ option.key }}
}
</option>
}
@case ('passwordinputgroup') {
<ng-template [ngTemplateOutlet]="label" />
<div class="input-group form-group" validationTarget>
<input
class="form-control"
[id]="prop.id"
[formControlName]="prop.name"
[abpShowPassword]="showPassword"
/>
<button class="btn btn-secondary" type="button" (click)="showPassword = !showPassword">
<i
class="fa"
aria-hidden="true"
[ngClass]="{
</select>
}
@case ('multiselect') {
<ng-template [ngTemplateOutlet]="label"></ng-template>
<abp-extensible-form-multi-select [prop]="prop" [options]="options$ | async" [formControlName]="prop.name"
[abpDisabled]="disabled" />
}
@case ('typeahead') {
<ng-template [ngTemplateOutlet]="label" />
<div #typeahead class="position-relative" validationStyle validationTarget>
<input #field [id]="prop.id" [autocomplete]="prop.autocomplete" [abpDisabled]="disabled" [ngbTypeahead]="search"
[editable]="false" [inputFormatter]="typeaheadFormatter" [resultFormatter]="typeaheadFormatter"
[ngModelOptions]="{ standalone: true }" [(ngModel)]="typeaheadModel"
(selectItem)="setTypeaheadValue($event.item)" (blur)="setTypeaheadValue(typeaheadModel)"
[class.is-invalid]="typeahead.classList.contains('is-invalid')" class="form-control" />
<input [formControlName]="prop.name" type="hidden" />
</div>
}
@case ('date') {
<ng-template [ngTemplateOutlet]="label" />
<input [id]="prop.id" [formControlName]="prop.name" (click)="datepicker.open()" (keyup.space)="datepicker.open()"
ngbDatepicker #datepicker="ngbDatepicker" type="text" class="form-control" />
}
@case ('time') {
<ng-template [ngTemplateOutlet]="label" />
<ngb-timepicker [formControlName]="prop.name" />
}
@case ('dateTime') {
<ng-template [ngTemplateOutlet]="label" />
<abp-extensible-date-time-picker [prop]="prop" [meridian]="meridian$ | async" />
}
@case ('textarea') {
<ng-template [ngTemplateOutlet]="label" />
<textarea #field [id]="prop.id" [formControlName]="prop.name" [abpDisabled]="disabled" [readonly]="readonly"
class="form-control"></textarea>
}
@case ('passwordinputgroup') {
<ng-template [ngTemplateOutlet]="label" />
<div class="input-group form-group" validationTarget>
<input class="form-control" [id]="prop.id" [formControlName]="prop.name" [abpShowPassword]="showPassword" />
<button class="btn btn-secondary" type="button" (click)="showPassword = !showPassword">
<i class="fa" aria-hidden="true" [class]="{
'fa-eye-slash': !showPassword,
'fa-eye': showPassword,
}"
></i>
</button>
</div>
}
}"></i>
</button>
</div>
}
}
@if (prop.formText) {
<small class="text-muted d-block">{{ prop.formText | abpLocalization }}</small>
<small class="text-muted d-block">{{ prop.formText | abpLocalization }}</small>
}
</div>
</ng-container>
<ng-template #label let-classes>
<label [htmlFor]="prop.id" [ngClass]="classes || 'form-label d-inline-block'">
<label [htmlFor]="prop.id" [class]="classes || 'form-label d-inline-block'">
<span class="d-inline-flex align-items-center gap-1 text-nowrap">
@if (prop.displayTextResolver) {
{{ prop.displayTextResolver(data) | abpLocalization }}
{{ prop.displayTextResolver(data) | abpLocalization }}
} @else {
@if (prop.isExtra) {
{{ '::' + prop.displayName | abpLocalization }}
} @else {
{{ prop.displayName | abpLocalization }}
}
@if (prop.isExtra) {
{{ '::' + prop.displayName | abpLocalization }}
} @else {
{{ prop.displayName | abpLocalization }}
}
}
{{ asterisk }}
@if (prop.tooltip) {
<i
[ngbTooltip]="prop.tooltip.text | abpLocalization"
[placement]="prop.tooltip.placement || 'auto'"
container="body"
class="bi bi-info-circle"
></i>
<i [ngbTooltip]="prop.tooltip.text | abpLocalization" [placement]="prop.tooltip.placement || 'auto'"
container="body" class="bi bi-info-circle"></i>
}
</span>
</label>
</ng-template>
</ng-template>

7
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form-prop.component.ts

@ -49,7 +49,7 @@ import { eExtensibleComponents } from '../../enums/components';
import { ExtensibleDateTimePickerComponent } from '../date-time-picker/extensible-date-time-picker.component';
import { NgxValidateCoreModule } from '@ngx-validate/core';
import { ExtensibleFormPropService } from '../../services/extensible-form-prop.service';
import { AsyncPipe, NgClass, NgComponentOutlet, NgTemplateOutlet } from '@angular/common';
import { AsyncPipe, NgComponentOutlet, NgTemplateOutlet } from '@angular/common';
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
import { ExtensibleFormMultiselectComponent } from '../multi-select/extensible-form-multiselect.component';
@ -70,11 +70,10 @@ import { ExtensibleFormMultiselectComponent } from '../multi-select/extensible-f
PermissionDirective,
LocalizationPipe,
AsyncPipe,
NgClass,
NgComponentOutlet,
NgTemplateOutlet,
FormsModule,
],
FormsModule
],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [ExtensibleFormPropService],
viewProviders: [

65
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form.component.html

@ -1,46 +1,35 @@
@if (form) {
@for (groupedProp of groupedPropList.items; track i; let i = $index; let first = $first) {
<ng-container *abpPropData="let data; fromList: groupedProp.formPropList; withRecord: record">
@if (isAnyGroupMemberVisible(i, data) && groupedProp.group?.className) {
<div
[ngClass]="groupedProp.group?.className"
[attr.data-name]="groupedProp.group?.name || groupedProp.group?.className"
>
<ng-container
[ngTemplateOutlet]="propListTemplate"
[ngTemplateOutletContext]="{ groupedProp: groupedProp, data: data, isFirstGroup: first}"
>
</ng-container>
</div>
} @else {
<ng-container
[ngTemplateOutlet]="propListTemplate"
[ngTemplateOutletContext]="{ groupedProp: groupedProp, data: data, isFirstGroup: first }"
>
</ng-container>
}
@for (groupedProp of groupedPropList.items; track i; let i = $index; let first = $first) {
<ng-container *abpPropData="let data; fromList: groupedProp.formPropList; withRecord: record">
@if (isAnyGroupMemberVisible(i, data) && groupedProp.group?.className) {
<div [class]="groupedProp.group?.className"
[attr.data-name]="groupedProp.group?.name || groupedProp.group?.className">
<ng-container [ngTemplateOutlet]="propListTemplate"
[ngTemplateOutletContext]="{ groupedProp: groupedProp, data: data, isFirstGroup: first}">
</ng-container>
</div>
} @else {
<ng-container [ngTemplateOutlet]="propListTemplate"
[ngTemplateOutletContext]="{ groupedProp: groupedProp, data: data, isFirstGroup: first }">
</ng-container>
}
</ng-container>
}
}
<ng-template let-groupedProp="groupedProp" let-data="data" let-isFirstGroup="isFirstGroup" #propListTemplate>
@for (prop of groupedProp.formPropList; let index = $index; let first = $first; track prop.name) {
@if (prop.visible(data)) {
@if (extraProperties.controls[prop.name]) {
<ng-container [formGroupName]="extraPropertiesKey">
<abp-extensible-form-prop [prop]="prop" [data]="data" [class]="prop.className" />
</ng-container>
} @else {
@if (form.get(prop.name)) {
<abp-extensible-form-prop
[class]="prop.className"
[prop]="prop"
[data]="data"
[first]="first"
[isFirstGroup]="isFirstGroup"
/>
}
}
}
@if (prop.visible(data)) {
@if (extraProperties.controls[prop.name]) {
<ng-container [formGroupName]="extraPropertiesKey">
<abp-extensible-form-prop [prop]="prop" [data]="data" [class]="prop.className" />
</ng-container>
} @else {
@if (form.get(prop.name)) {
<abp-extensible-form-prop [class]="prop.className" [prop]="prop" [data]="data" [first]="first"
[isFirstGroup]="isFirstGroup" />
}
}
}
}
</ng-template>
</ng-template>

4
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form.component.ts

@ -17,14 +17,14 @@ import { ExtensionsService } from '../../services/extensions.service';
import { EXTENSIONS_IDENTIFIER } from '../../tokens/extensions.token';
import { selfFactory } from '../../utils/factory.util';
import { ExtensibleFormPropComponent } from './extensible-form-prop.component';
import { NgClass, NgTemplateOutlet } from '@angular/common';
import { NgTemplateOutlet } from '@angular/common';
import { PropDataDirective } from '../../directives/prop-data.directive';
@Component({
exportAs: 'abpExtensibleForm',
selector: 'abp-extensible-form',
templateUrl: './extensible-form.component.html',
imports: [NgClass, NgTemplateOutlet, PropDataDirective, ReactiveFormsModule, ExtensibleFormPropComponent],
imports: [NgTemplateOutlet, PropDataDirective, ReactiveFormsModule, ExtensibleFormPropComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
viewProviders: [
{

4
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html

@ -94,7 +94,7 @@
: ('::' + (row['_' + prop.name]?.value | async | abpUtcToLocal:prop.type) | abpLocalization)
" (click)="
prop.action && prop.action({ getInjected: getInjected, record: row, index: i })
" [ngClass]="entityPropTypeClasses[prop.type]" [class.pointer]="prop.action"></div>
" [class]="entityPropTypeClasses[prop.type]" [class.pointer]="prop.action"></div>
} @else {
<div [innerHTML]="
!prop.isExtra
@ -102,7 +102,7 @@
: ('::' + (row['_' + prop.name]?.value | async) | abpLocalization)
" (click)="
prop.action && prop.action({ getInjected: getInjected, record: row, index: i })
" [ngClass]="entityPropTypeClasses[prop.type]" [class.pointer]="prop.action"></div>
" [class]="entityPropTypeClasses[prop.type]" [class.pointer]="prop.action"></div>
}
} @else {
<ng-container *ngComponentOutlet="

103
npm/ng-packs/packages/components/extensible/src/lib/components/grid-actions/grid-actions.component.html

@ -1,88 +1,55 @@
@if (actionList.length > 1) {
<div ngbDropdown container="body" class="d-inline-block">
<button
class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
ngbDropdownToggle
>
<i [ngClass]="icon" [class.me-1]="icon"></i>{{ text | abpLocalization }}
</button>
<div ngbDropdownMenu>
@for (action of actionList; track action.text) {
<ng-container
[ngTemplateOutlet]="dropDownBtnItemTmp"
[ngTemplateOutletContext]="{ $implicit: action }"
>
</ng-container>
}
</div>
<div ngbDropdown container="body" class="d-inline-block">
<button class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" ngbDropdownToggle>
<i [class]="icon" [class.me-1]="icon"></i>{{ text | abpLocalization }}
</button>
<div ngbDropdownMenu>
@for (action of actionList; track action.text) {
<ng-container [ngTemplateOutlet]="dropDownBtnItemTmp" [ngTemplateOutletContext]="{ $implicit: action }">
</ng-container>
}
</div>
</div>
}
@if (actionList.length === 1) {
<ng-container
[ngTemplateOutlet]="btnTmp"
[ngTemplateOutletContext]="{ $implicit: actionList.get(0).value }"
></ng-container>
<ng-container [ngTemplateOutlet]="btnTmp"
[ngTemplateOutletContext]="{ $implicit: actionList.get(0).value }"></ng-container>
}
<ng-template #dropDownBtnItemTmp let-action>
@if (action.visible(data)) {
<button
ngbDropdownItem
*abpPermission="action.permission; runChangeDetection: false"
(click)="action.action(data)"
type="button"
>
<ng-container
*ngTemplateOutlet="buttonContentTmp; context: { $implicit: action }"
></ng-container>
</button>
<button ngbDropdownItem *abpPermission="action.permission; runChangeDetection: false" (click)="action.action(data)"
type="button">
<ng-container *ngTemplateOutlet="buttonContentTmp; context: { $implicit: action }"></ng-container>
</button>
}
</ng-template>
<ng-template #buttonContentTmp let-action>
<i [ngClass]="action.icon" [class.me-1]="action.icon && !action.showOnlyIcon"></i>
<i [class]="action.icon" [class.me-1]="action.icon && !action.showOnlyIcon"></i>
@if (!action.showOnlyIcon) {
@if (action.icon) {
<span>{{ action.text | abpLocalization }}</span>
} @else {
<div abpEllipsis>{{ action.text | abpLocalization }}</div>
}
@if (action.icon) {
<span>{{ action.text | abpLocalization }}</span>
} @else {
<div abpEllipsis>{{ action.text | abpLocalization }}</div>
}
}
</ng-template>
<ng-template #btnTmp let-action>
@if (action.visible(data)) {
@if (action.tooltip) {
<button
*abpPermission="action.permission; runChangeDetection: false"
(click)="action.action(data)"
type="button"
[class]="action.btnClass"
[style]="action.btnStyle"
[ngbTooltip]="action.tooltip.text | abpLocalization"
[placement]="action.tooltip.placement || 'auto'"
triggers="hover"
container="body"
>
<ng-container
*ngTemplateOutlet="buttonContentTmp; context: { $implicit: action }"
></ng-container>
</button>
} @else {
<button
*abpPermission="action.permission; runChangeDetection: false"
(click)="action.action(data)"
type="button"
[class]="action.btnClass"
[style]="action.btnStyle"
>
<ng-container
*ngTemplateOutlet="buttonContentTmp; context: { $implicit: action }"
></ng-container>
</button>
}
@if (action.tooltip) {
<button *abpPermission="action.permission; runChangeDetection: false" (click)="action.action(data)" type="button"
[class]="action.btnClass" [style]="action.btnStyle" [ngbTooltip]="action.tooltip.text | abpLocalization"
[placement]="action.tooltip.placement || 'auto'" triggers="hover" container="body">
<ng-container *ngTemplateOutlet="buttonContentTmp; context: { $implicit: action }"></ng-container>
</button>
} @else {
<button *abpPermission="action.permission; runChangeDetection: false" (click)="action.action(data)" type="button"
[class]="action.btnClass" [style]="action.btnStyle">
<ng-container *ngTemplateOutlet="buttonContentTmp; context: { $implicit: action }"></ng-container>
</button>
}
</ng-template>
}
</ng-template>

13
npm/ng-packs/packages/components/extensible/src/lib/components/grid-actions/grid-actions.component.ts

@ -1,8 +1,8 @@
import {
ChangeDetectionStrategy,
Component,
Input,
TrackByFunction,
import {
ChangeDetectionStrategy,
Component,
Input,
TrackByFunction,
} from '@angular/core';
import { EntityAction, EntityActionList } from '../../models/entity-actions';
import { EXTENSIONS_ACTION_TYPE } from '../../tokens/extensions.token';
@ -10,7 +10,7 @@ import { AbstractActionsComponent } from '../abstract-actions/abstract-actions.c
import { NgbDropdownModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
import { LocalizationPipe, PermissionDirective } from '@abp/ng.core';
import { EllipsisDirective } from '@abp/ng.theme.shared';
import { NgClass, NgTemplateOutlet } from '@angular/common';
import { NgTemplateOutlet } from '@angular/common';
@Component({
exportAs: 'abpGridActions',
@ -18,7 +18,6 @@ import { NgClass, NgTemplateOutlet } from '@angular/common';
NgbDropdownModule,
EllipsisDirective,
PermissionDirective,
NgClass,
LocalizationPipe,
NgTemplateOutlet,
NgbTooltipModule,

26
npm/ng-packs/packages/components/extensible/src/lib/components/page-toolbar/page-toolbar.component.html

@ -4,26 +4,20 @@
@if (action.visible(data)) {
<ng-container *abpPermission="action.permission; runChangeDetection: false">
@if (action.component; as component) {
<ng-container
*ngComponentOutlet="component; injector: record | createInjector: action:this"
></ng-container>
<ng-container *ngComponentOutlet="component; injector: record | createInjector: action:this"></ng-container>
}@else {
@if (asToolbarAction(action).value; as toolbarAction ) {
<button
(click)="action.action(data)"
type="button"
[ngClass]="toolbarAction?.btnClass ? toolbarAction?.btnClass : defaultBtnClass"
class="d-inline-flex align-items-center gap-1"
>
<i [ngClass]="toolbarAction?.icon" [class.me-1]="toolbarAction?.icon"></i>
{{ toolbarAction?.text | abpLocalization }}
</button>
}
@if (asToolbarAction(action).value; as toolbarAction ) {
<button (click)="action.action(data)" type="button"
[class]="toolbarAction?.btnClass ? toolbarAction?.btnClass : defaultBtnClass"
class="d-inline-flex align-items-center gap-1">
<i [class]="toolbarAction?.icon" [class.me-1]="toolbarAction?.icon"></i>
{{ toolbarAction?.text | abpLocalization }}
</button>
}
}
</ng-container>
}
</div>
}
</div>
</div>

8
npm/ng-packs/packages/components/extensible/src/lib/components/page-toolbar/page-toolbar.component.ts

@ -10,7 +10,7 @@ import { EXTENSIONS_ACTION_TYPE } from '../../tokens/extensions.token';
import { AbstractActionsComponent } from '../abstract-actions/abstract-actions.component';
import { CreateInjectorPipe } from '../../pipes/create-injector.pipe';
import { LocalizationPipe, PermissionDirective } from '@abp/ng.core';
import { NgClass, NgComponentOutlet } from '@angular/common';
import { NgComponentOutlet } from '@angular/common';
@Component({
exportAs: 'abpPageToolbar',
@ -19,7 +19,6 @@ import { NgClass, NgComponentOutlet } from '@angular/common';
CreateInjectorPipe,
PermissionDirective,
LocalizationPipe,
NgClass,
NgComponentOutlet,
],
templateUrl: './page-toolbar.component.html',
@ -33,8 +32,7 @@ import { NgClass, NgComponentOutlet } from '@angular/common';
})
export class PageToolbarComponent<R = any>
extends AbstractActionsComponent<ToolbarActionList<R>>
implements HasCreateInjectorPipe<R>
{
implements HasCreateInjectorPipe<R> {
readonly injector: Injector;
defaultBtnClass = 'btn btn-sm btn-primary';
@ -48,7 +46,7 @@ export class PageToolbarComponent<R = any>
const injector = inject(Injector);
super();
this.injector = injector;
}

4
npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.ts

@ -12,7 +12,7 @@ import {
inject,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { NgTemplateOutlet } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { LocalizationPipe } from '@abp/ng.core';
import { Subject, Observable, debounceTime, distinctUntilChanged, of, finalize } from 'rxjs';
@ -29,7 +29,7 @@ export type LookupSearchFn<T = LookupItem> = (filter: string) => Observable<T[]>
selector: 'abp-lookup-search',
templateUrl: './lookup-search.component.html',
styleUrl: './lookup-search.component.scss',
imports: [CommonModule, FormsModule, LocalizationPipe],
imports: [FormsModule, LocalizationPipe, NgTemplateOutlet],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LookupSearchComponent<T extends LookupItem = LookupItem> implements OnInit {

218
npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.html

@ -1,13 +1,13 @@
@if (visible) {
<abp-modal [(visible)]="visible" [busy]="modalBusy" [options]="{ size: 'lg' }">
<ng-template #abpHeader>
<h3>
{{ 'AbpFeatureManagement::Features' | abpLocalization }}
@if (providerTitle) {
- {{ providerTitle }}
}
</h3>
</ng-template>
<abp-modal [(visible)]="visible" [busy]="modalBusy" [options]="{ size: 'lg' }">
<ng-template #abpHeader>
<h3>
{{ 'AbpFeatureManagement::Features' | abpLocalization }}
@if (providerTitle) {
- {{ providerTitle }}
}
</h3>
</ng-template>
<ng-template #abpBody>
<div class="row">
@ -35,93 +35,72 @@
<h4>{{ selectedGroupDisplayName }}</h4>
<hr class="mt-2 mb-3" />
@for (feature of features[group.name]; track feature.id || i; let i = $index) {
@let provider = feature.provider.name;
@let isFeatureDisabled = !feature.parentName ? isParentDisabled(feature.name, group.name, provider) :
(provider !== providerName && provider !== defaultProviderName);
@for (feature of features[group.name]; track feature.id || i; let i = $index) {
@let provider = feature.provider.name;
@let isFeatureDisabled = !feature.parentName ? isParentDisabled(feature.name, group.name, provider) :
(provider !== providerName && provider !== defaultProviderName);
<div class="mt-2" [ngStyle]="feature.style" (keyup.enter)="save()">
@switch (feature.valueType?.name) {
@case (valueTypes.ToggleStringValueType) {
<div class="form-check" [class.px-4]="!!feature.parentName">
<input
class="form-check-input"
type="checkbox"
[id]="feature.name"
[(ngModel)]="feature.value"
(ngModelChange)="onCheckboxClick($event, feature)"
[disabled]="isFeatureDisabled"
/>
<div class="mt-2" [style]="feature.style" (keyup.enter)="save()">
@switch (feature.valueType?.name) {
@case (valueTypes.ToggleStringValueType) {
<div class="form-check" [class.px-4]="!!feature.parentName">
<input class="form-check-input" type="checkbox" [id]="feature.name" [(ngModel)]="feature.value"
(ngModelChange)="onCheckboxClick($event, feature)" [disabled]="isFeatureDisabled" />
<label class="form-check-label" [htmlFor]="feature.name">
{{ feature.displayName }}
@if (isFeatureDisabled) {
<span>({{ provider }})</span>
}
</label>
<ng-container
*ngTemplateOutlet="
<label class="form-check-label" [htmlFor]="feature.name">
{{ feature.displayName }}
@if (isFeatureDisabled) {
<span>({{ provider }})</span>
}
</label>
<ng-container *ngTemplateOutlet="
descTmp;
context: { $implicit: feature.description }
"
></ng-container>
</div>
}
@case (valueTypes.FreeTextStringValueType) {
<div class="mb-3 form-group" [class.px-2]="!!feature.parentName">
<label [htmlFor]="feature.name" class="form-label">
{{ feature.displayName }}
@if (isFeatureDisabled) {
<span>({{ provider }})</span>
}
</label>
<input
class="form-control"
type="text"
[id]="feature.name"
[(ngModel)]="feature.value"
[abpFeatureManagementFreeText]="feature"
[disabled]="isFeatureDisabled"
/>
"></ng-container>
</div>
}
@case (valueTypes.FreeTextStringValueType) {
<div class="mb-3 form-group" [class.px-2]="!!feature.parentName">
<label [htmlFor]="feature.name" class="form-label">
{{ feature.displayName }}
@if (isFeatureDisabled) {
<span>({{ provider }})</span>
}
</label>
<input class="form-control" type="text" [id]="feature.name" [(ngModel)]="feature.value"
[abpFeatureManagementFreeText]="feature" [disabled]="isFeatureDisabled" />
<ng-container
*ngTemplateOutlet="
<ng-container *ngTemplateOutlet="
descTmp;
context: { $implicit: feature.description }
"
></ng-container>
</div>
}
@case (valueTypes.SelectionStringValueType) {
@if (feature.valueType.itemSource?.items?.length) {
<div class="mb-3 form-group" [class.px-2]="!!feature.parentName">
<label [htmlFor]="feature.name" class="form-label">
{{ feature.displayName }}
@if (isFeatureDisabled) {
<span>({{ provider }})</span>
}
</label>
<select
class="form-select"
[id]="feature.name"
[(ngModel)]="feature.value"
[disabled]="isFeatureDisabled"
>
@for (
item of feature.valueType.itemSource?.items;
track item.value
) {
<option [ngValue]="item.value">
{{
item.displayText?.resourceName +
'::' +
item.displayText?.name | abpLocalization
}}
</option>
}
</select>
<ng-container
*ngTemplateOutlet="
"></ng-container>
</div>
}
@case (valueTypes.SelectionStringValueType) {
@if (feature.valueType.itemSource?.items?.length) {
<div class="mb-3 form-group" [class.px-2]="!!feature.parentName">
<label [htmlFor]="feature.name" class="form-label">
{{ feature.displayName }}
@if (isFeatureDisabled) {
<span>({{ provider }})</span>
}
</label>
<select class="form-select" [id]="feature.name" [(ngModel)]="feature.value"
[disabled]="isFeatureDisabled">
@for (
item of feature.valueType.itemSource?.items;
track item.value
) {
<option [ngValue]="item.value">
{{
item.displayText?.resourceName +
'::' +
item.displayText?.name | abpLocalization
}}
</option>
}
</select>
<ng-container *ngTemplateOutlet="
descTmp;
context: { $implicit: feature.description }
"
@ -148,34 +127,43 @@
</div>
}
</div>
</ng-template>
<ng-template #abpFooter>
<button abpClose type="button" class="btn btn-link">
{{ 'AbpFeatureManagement::Cancel' | abpLocalization }}
</button>
<ng-template #descTmp let-description>
@if (description) {
<small class="d-block form-text text-muted">{{ description }}</small>
}
</ng-template>
@if (groups.length) {
<abp-button
buttonClass="btn btn-outline-primary"
[disabled]="modalBusy"
(click)="resetToDefault()"
aria-hidden="true"
>
{{ 'AbpFeatureManagement::ResetToDefault' | abpLocalization }}
</abp-button>
<div class="col-md-8">
<div class="py-0" [ngbNavOutlet]="nav"></div>
</div>
}
@if (groups.length) {
<abp-button
iconClass="fa fa-check"
[disabled]="modalBusy"
(click)="save()"
aria-hidden="true"
>
{{ 'AbpFeatureManagement::Save' | abpLocalization }}
</abp-button>
@if (!groups.length) {
<div class="col">
{{ 'AbpFeatureManagement::NoFeatureFoundMessage' | abpLocalization }}
</div>
}
</ng-template>
</abp-modal>
}
</div>
</ng-template>
<ng-template #abpFooter>
<button abpClose type="button" class="btn btn-link">
{{ 'AbpFeatureManagement::Cancel' | abpLocalization }}
</button>
@if (groups.length) {
<abp-button buttonClass="btn btn-outline-primary" [disabled]="modalBusy" (click)="resetToDefault()"
aria-hidden="true">
{{ 'AbpFeatureManagement::ResetToDefault' | abpLocalization }}
</abp-button>
}
@if (groups.length) {
<abp-button iconClass="fa fa-check" [disabled]="modalBusy" (click)="save()" aria-hidden="true">
{{ 'AbpFeatureManagement::Save' | abpLocalization }}
</abp-button>
}
</ng-template>
</abp-modal>
}

3
npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts

@ -31,7 +31,7 @@ import {
import { concat, of } from 'rxjs';
import { finalize, switchMap, take, tap } from 'rxjs/operators';
import { PermissionManagement } from '../models';
import { NgStyle } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Tabs, TabList, Tab, TabPanel, TabContent } from '@angular/aria/tabs';
@ -97,7 +97,6 @@ type PermissionWithGroupName = PermissionGrantInfoDto & {
],
imports: [
FormsModule,
NgStyle,
ModalComponent,
LocalizationPipe,
ButtonComponent,

7
npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.ts

@ -25,7 +25,7 @@ import {
PermissionDirective
} from '@abp/ng.core';
import { NgxValidateCoreModule } from '@ngx-validate/core';
import { CommonModule } from '@angular/common';
const { required, email } = Validators;
@ -35,14 +35,13 @@ const { required, email } = Validators;
animations: [collapse],
imports: [
ReactiveFormsModule,
CommonModule,
LocalizationPipe,
ButtonComponent,
ModalComponent,
ModalCloseDirective,
NgxValidateCoreModule,
PermissionDirective,
],
PermissionDirective
],
})
export class EmailSettingGroupComponent implements OnInit {
private emailSettingsService = inject(EmailSettingsService);

36
npm/ng-packs/packages/theme-basic/src/lib/components/page-alert-container/page-alert-container.component.html

@ -1,26 +1,12 @@
@for (alert of service.alerts$ | async; track i; let i = $index) {
<div
class="alert alert-{{ alert.type }} fade show"
[ngClass]="{ 'alert-dismissible fade show': alert.dismissible }"
role="alert"
>
@if (alert.title) {
<h4
class="alert-heading"
[innerHTML]="alert.title | abpSafeHtml | abpLocalization: alert.titleLocalizationParams"
></h4>
}
<span
[innerHTML]="alert.message | abpSafeHtml | abpLocalization: alert.messageLocalizationParams"
></span>
@if (alert.dismissible) {
<button
type="button"
class="btn-close"
data-dismiss="alert"
aria-label="Close"
(click)="service.remove(i)"
></button>
}
</div>
}
<div class="alert alert-{{ alert.type }} fade show" [class.alert-dismissible]="alert.dismissible" role="alert">
@if (alert.title) {
<h4 class="alert-heading" [innerHTML]="alert.title | abpSafeHtml | abpLocalization: alert.titleLocalizationParams">
</h4>
}
<span [innerHTML]="alert.message | abpSafeHtml | abpLocalization: alert.messageLocalizationParams"></span>
@if (alert.dismissible) {
<button type="button" class="btn-close" data-dismiss="alert" aria-label="Close" (click)="service.remove(i)"></button>
}
</div>
}

4
npm/ng-packs/packages/theme-basic/src/lib/components/page-alert-container/page-alert-container.component.ts

@ -1,13 +1,13 @@
import { Component, ViewEncapsulation, inject } from '@angular/core';
import { PageAlertService } from '@abp/ng.theme.shared';
import { NgClass, AsyncPipe } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { LocalizationPipe, SafeHtmlPipe } from '@abp/ng.core';
@Component({
selector: 'abp-page-alert-container',
templateUrl: './page-alert-container.component.html',
encapsulation: ViewEncapsulation.None,
imports: [NgClass, AsyncPipe, LocalizationPipe, SafeHtmlPipe],
imports: [AsyncPipe, LocalizationPipe, SafeHtmlPipe],
})
export class PageAlertContainerComponent {
service = inject(PageAlertService);

102
npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.html

@ -1,16 +1,14 @@
<ul class="navbar-nav">
@for (route of routesService.visible$ | async; track $index) {
<ng-container
[ngTemplateOutlet]="isDropdown(route) ? dropdownLink : defaultLink"
[ngTemplateOutletContext]="{ $implicit: route }"
/>
<ng-container [ngTemplateOutlet]="isDropdown(route) ? dropdownLink : defaultLink"
[ngTemplateOutletContext]="{ $implicit: route }" />
}
<ng-template #defaultLink let-route>
<li class="nav-item" *abpPermission="route.requiredPolicy">
<a class="nav-link" [routerLink]="[route.path]">
@if (route.iconClass) {
<i [ngClass]="route.iconClass"></i>
<i [class]="route.iconClass"></i>
}
{{ route.name | abpAsyncLocalization | async }}
</a>
@ -19,91 +17,61 @@
<ng-template #dropdownLink let-route>
@if (route.children?.length) {
<li
class="nav-item dropdown"
display="static"
*abpPermission="route.requiredPolicy"
(click)="
<li class="nav-item dropdown" display="static" *abpPermission="route.requiredPolicy" (click)="
rootDropdownExpand[route.name]
? (rootDropdownExpand[route.name] = false)
: (rootDropdownExpand[route.name] = true)
"
>
<a
class="nav-link dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
href="javascript:void(0)"
>
@if (route.iconClass) {
<i [ngClass]="route.iconClass"></i>
}
{{ route.name | abpAsyncLocalization | async }}
</a>
<div
#routeContainer
class="dropdown-menu border-0 shadow-sm"
(click)="$event.preventDefault(); $event.stopPropagation()"
[class.d-block]="smallScreen && rootDropdownExpand[route.name]"
>
<ng-container *ngTemplateOutlet="forTemplate; context: { $implicit: route }" />
</div>
</li>
: (rootDropdownExpand[route.name] = true)">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
href="javascript:void(0)">
@if (route.iconClass) {
<i [class]="route.iconClass"></i>
}
{{ route.name | abpAsyncLocalization | async }}
</a>
<div #routeContainer class="dropdown-menu border-0 shadow-sm"
(click)="$event.preventDefault(); $event.stopPropagation()"
[class.d-block]="smallScreen && rootDropdownExpand[route.name]">
<ng-container *ngTemplateOutlet="forTemplate; context: { $implicit: route }" />
</div>
</li>
}
</ng-template>
<ng-template #forTemplate let-route>
@for (child of route.children; track $index) {
<ng-template
[ngTemplateOutlet]="child.children?.length ? dropdownChild : defaultChild"
[ngTemplateOutletContext]="{ $implicit: child }"
/>
<ng-template [ngTemplateOutlet]="child.children?.length ? dropdownChild : defaultChild"
[ngTemplateOutletContext]="{ $implicit: child }" />
}
</ng-template>
<ng-template #defaultChild let-child>
@if (child.path) {
<div class="dropdown-submenu" *abpPermission="child.requiredPolicy">
<a class="dropdown-item" [routerLink]="[child.path]" (click)="closeDropdown()">
@if (child.iconClass) {
<i [ngClass]="child.iconClass"></i>
}
{{ child.name | abpLocalization }}</a
>
</div>
<div class="dropdown-submenu" *abpPermission="child.requiredPolicy">
<a class="dropdown-item" [routerLink]="[child.path]" (click)="closeDropdown()">
@if (child.iconClass) {
<i [class]="child.iconClass"></i>
}
{{ child.name | abpLocalization }}</a>
</div>
}
</ng-template>
<ng-template #dropdownChild let-child>
<div
class="dropdown-submenu"
ngbDropdown
#dropdownSubmenu="ngbDropdown"
placement="right-top"
[autoClose]="true"
*abpPermission="child.requiredPolicy"
>
<div class="dropdown-submenu" ngbDropdown #dropdownSubmenu="ngbDropdown" placement="right-top" [autoClose]="true"
*abpPermission="child.requiredPolicy">
<div ngbDropdownToggle [class.dropdown-toggle]="false">
<a
abpEllipsis="210px"
[abpEllipsisEnabled]="!smallScreen"
role="button"
class="btn d-block text-start dropdown-toggle"
>
<a abpEllipsis="210px" [abpEllipsisEnabled]="!smallScreen" role="button"
class="btn d-block text-start dropdown-toggle">
@if (child.iconClass) {
<i [ngClass]="child.iconClass"></i>
<i [class]="child.iconClass"></i>
}
{{ child.name | abpLocalization }}
</a>
</div>
<div
#childrenContainer
class="dropdown-menu dropdown-menu-start border-0 shadow-sm"
[class.d-block]="smallScreen && dropdownSubmenu.isOpen()"
>
<div #childrenContainer class="dropdown-menu dropdown-menu-start border-0 shadow-sm"
[class.d-block]="smallScreen && dropdownSubmenu.isOpen()">
<ng-container *ngTemplateOutlet="forTemplate; context: { $implicit: child }" />
</div>
</div>
</ng-template>
</ul>
</ul>

3
npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts

@ -16,7 +16,7 @@ import {
TrackByFunction,
ViewChildren,
} from '@angular/core';
import { NgTemplateOutlet, NgClass, AsyncPipe } from '@angular/common';
import { NgTemplateOutlet, AsyncPipe } from '@angular/common';
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { RouterLink } from '@angular/router';
import { EllipsisDirective } from '@abp/ng.theme.shared';
@ -26,7 +26,6 @@ import { EllipsisDirective } from '@abp/ng.theme.shared';
templateUrl: 'routes.component.html',
imports: [
NgTemplateOutlet,
NgClass,
AsyncPipe,
RouterLink,
NgbDropdownModule,

7
npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts

@ -10,7 +10,6 @@ import {
ViewChild,
inject,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { ABP, StopPropagationDirective } from '@abp/ng.core';
@Component({
@ -21,16 +20,16 @@ import { ABP, StopPropagationDirective } from '@abp/ng.core';
[id]="buttonId"
[attr.type]="buttonType"
[attr.form]="formName"
[ngClass]="buttonClass"
[class]="buttonClass"
[disabled]="loading || disabled"
(click.stop)="click.next($event); abpClick.next($event)"
(focus)="focus.next($event); abpFocus.next($event)"
(blur)="blur.next($event); abpBlur.next($event)"
>
<i [ngClass]="icon" class="me-1" aria-hidden="true"></i><ng-content></ng-content>
<i [class]="icon" class="me-1" aria-hidden="true"></i><ng-content></ng-content>
</button>
`,
imports: [CommonModule, StopPropagationDirective],
imports: [StopPropagationDirective],
})
export class ButtonComponent implements OnInit {
private renderer = inject(Renderer2);

4
npm/ng-packs/packages/theme-shared/src/lib/components/card/card-body.component.ts

@ -1,12 +1,10 @@
import { Component, HostBinding, Input } from '@angular/core';
import { NgClass, NgStyle } from '@angular/common';
@Component({
selector: 'abp-card-body',
template: ` <div [ngClass]="cardBodyClass" [ngStyle]="cardBodyStyle">
template: ` <div [class]="cardBodyClass" [style]="cardBodyStyle">
<ng-content></ng-content>
</div>`,
imports: [NgClass, NgStyle],
})
export class CardBodyComponent {
@HostBinding('class') componentClass = 'card-body';

5
npm/ng-packs/packages/theme-shared/src/lib/components/card/card-footer.component.ts

@ -1,15 +1,14 @@
import { Component, HostBinding, Input } from '@angular/core';
import { NgClass, NgStyle } from '@angular/common';
@Component({
selector: 'abp-card-footer',
template: `
<div [ngStyle]="cardFooterStyle" [ngClass]="cardFooterClass">
<div [style]="cardFooterStyle" [class]="cardFooterClass">
<ng-content></ng-content>
</div>
`,
styles: [],
imports: [NgClass, NgStyle],
imports: [],
})
export class CardFooterComponent {
@HostBinding('class') componentClass = 'card-footer';

5
npm/ng-packs/packages/theme-shared/src/lib/components/card/card-header.component.ts

@ -1,15 +1,14 @@
import { Component, HostBinding, Input } from '@angular/core';
import { NgClass, NgStyle } from '@angular/common';
@Component({
selector: 'abp-card-header',
template: `
<div [ngClass]="cardHeaderClass" [ngStyle]="cardHeaderStyle">
<div [class]="cardHeaderClass" [style]="cardHeaderStyle">
<ng-content></ng-content>
</div>
`,
styles: [],
imports: [NgClass, NgStyle],
imports: [],
})
export class CardHeaderComponent {
@HostBinding('class') componentClass = 'card-header';

5
npm/ng-packs/packages/theme-shared/src/lib/components/card/card.component.ts

@ -1,12 +1,11 @@
import { Component, Input } from '@angular/core';
import { NgClass, NgStyle } from '@angular/common';
@Component({
selector: 'abp-card',
template: ` <div class="card" [ngClass]="cardClass" [ngStyle]="cardStyle">
template: ` <div class="card" [class]="cardClass" [style]="cardStyle">
<ng-content></ng-content>
</div>`,
imports: [NgClass, NgStyle],
imports: [],
})
export class CardComponent {
@Input() cardClass: string;

13
npm/ng-packs/packages/theme-shared/src/lib/components/checkbox/checkbox.component.ts

@ -1,6 +1,5 @@
import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core';
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import { NgClass, NgStyle } from '@angular/common';
import { AbstractNgModelComponent, LocalizationPipe } from '@abp/ng.core';
@Component({
@ -12,13 +11,13 @@ import { AbstractNgModelComponent, LocalizationPipe } from '@abp/ng.core';
[(ngModel)]="value"
[id]="checkboxId"
[readonly]="checkboxReadonly"
[ngClass]="checkboxClass"
[ngStyle]="checkboxStyle"
[class]="checkboxClass"
[style]="checkboxStyle"
(blur)="checkboxBlur.next()"
(focus)="checkboxFocus.next()"
/>
@if (label) {
<label [ngClass]="labelClass" [for]="checkboxId">
<label [class]="labelClass" [for]="checkboxId">
{{ label | abpLocalization }}
</label>
}
@ -31,7 +30,7 @@ import { AbstractNgModelComponent, LocalizationPipe } from '@abp/ng.core';
multi: true,
},
],
imports: [NgClass, NgStyle, FormsModule, LocalizationPipe],
imports: [FormsModule, LocalizationPipe],
})
export class FormCheckboxComponent extends AbstractNgModelComponent {
@Input() label?: string;
@ -39,8 +38,8 @@ export class FormCheckboxComponent extends AbstractNgModelComponent {
@Input() checkboxId!: string;
@Input() checkboxStyle:
| {
[klass: string]: any;
}
[klass: string]: any;
}
| null
| undefined;
@Input() checkboxClass = 'form-check-input';

77
npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.html

@ -1,51 +1,34 @@
@if (confirmation$ | async; as data) {
<div class="confirmation">
<div
class="confirmation-backdrop"
(click)="data.options?.dismissible ? close(dismiss) : null"
></div>
<div class="confirmation-dialog">
@if (data.severity || isCustomIconExists(data)) {
<div class="icon-container" [ngClass]="data.severity">
@if (isIconTemplateExits(data)) {
<div [outerHTML]="data.options.iconTemplate"></div>
} @else {
<i class="icon" [ngClass]="getIconClass(data)"></i>
}
</div>
<div class="confirmation">
<div class="confirmation-backdrop" (click)="data.options?.dismissible ? close(dismiss) : null"></div>
<div class="confirmation-dialog">
@if (data.severity || isCustomIconExists(data)) {
<div class="icon-container" [class]="data.severity">
@if (isIconTemplateExits(data)) {
<div [outerHTML]="data.options.iconTemplate"></div>
} @else {
<i class="icon" [class]="getIconClass(data)"></i>
}
</div>
}
<div class="content">
@if (data.title) {
<h1 class="title" [innerHTML]="data.title | abpLocalization: data.options?.titleLocalizationParams"></h1>
}
@if (data.message) {
<p class="message" [innerHTML]="data.message | abpLocalization: data.options?.messageLocalizationParams"></p>
}
</div>
<div class="footer">
@if (!data?.options?.hideCancelBtn) {
<button id="cancel" class="btn btn-outline-primary me-2"
[innerHTML]="data.options?.cancelText || 'AbpUi::Cancel' | abpLocalization" (click)="close(reject)"></button>
}
@if (!data?.options?.hideYesBtn) {
<button id="confirm" class="btn btn-primary" [innerHTML]="data.options?.yesText || 'AbpUi::Yes' | abpLocalization"
(click)="close(confirm)"></button>
}
<div class="content">
@if (data.title) {
<h1
class="title"
[innerHTML]="data.title | abpLocalization: data.options?.titleLocalizationParams"
></h1>
}
@if (data.message) {
<p
class="message"
[innerHTML]="data.message | abpLocalization: data.options?.messageLocalizationParams"
></p>
}
</div>
<div class="footer">
@if (!data?.options?.hideCancelBtn) {
<button
id="cancel"
class="btn btn-outline-primary me-2"
[innerHTML]="data.options?.cancelText || 'AbpUi::Cancel' | abpLocalization"
(click)="close(reject)"
></button>
}
@if (!data?.options?.hideYesBtn) {
<button
id="confirm"
class="btn btn-primary"
[innerHTML]="data.options?.yesText || 'AbpUi::Yes' | abpLocalization"
(click)="close(confirm)"
></button>
}
</div>
</div>
</div>
}
</div>
}

4
npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts

@ -1,4 +1,4 @@
import { NgClass, AsyncPipe } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { Component, inject } from '@angular/core';
import { ReplaySubject } from 'rxjs';
import { Confirmation } from '../../models/confirmation';
@ -9,7 +9,7 @@ import { LocalizationPipe } from '@abp/ng.core';
selector: 'abp-confirmation',
templateUrl: './confirmation.component.html',
styleUrls: ['./confirmation.component.scss'],
imports: [NgClass, AsyncPipe, LocalizationPipe],
imports: [AsyncPipe, LocalizationPipe],
})
export class ConfirmationComponent {
private icons = inject<ConfirmationIcons>(CONFIRMATION_ICONS);

13
npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts

@ -1,6 +1,5 @@
import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core';
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import { NgClass, NgStyle } from '@angular/common';
import { AbstractNgModelComponent, LocalizationPipe } from '@abp/ng.core';
@Component({
@ -8,7 +7,7 @@ import { AbstractNgModelComponent, LocalizationPipe } from '@abp/ng.core';
template: `
<div class="mb-3">
@if (label) {
<label [ngClass]="labelClass" [for]="inputId">
<label [class]="labelClass" [for]="inputId">
{{ label | abpLocalization }}
</label>
}
@ -17,8 +16,8 @@ import { AbstractNgModelComponent, LocalizationPipe } from '@abp/ng.core';
[id]="inputId"
[placeholder]="inputPlaceholder"
[readonly]="inputReadonly"
[ngClass]="inputClass"
[ngStyle]="inputStyle"
[class]="inputClass"
[style]="inputStyle"
(blur)="formBlur.next()"
(focus)="formFocus.next()"
[(ngModel)]="value"
@ -32,7 +31,7 @@ import { AbstractNgModelComponent, LocalizationPipe } from '@abp/ng.core';
multi: true,
},
],
imports: [NgClass, NgStyle, LocalizationPipe, FormsModule],
imports: [LocalizationPipe, FormsModule],
})
export class FormInputComponent extends AbstractNgModelComponent {
@Input() inputId!: string;
@ -42,8 +41,8 @@ export class FormInputComponent extends AbstractNgModelComponent {
@Input() inputPlaceholder = '';
@Input() inputStyle:
| {
[klass: string]: any;
}
[klass: string]: any;
}
| null
| undefined;
@Input() inputClass = 'form-control';

4
npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.ts

@ -14,7 +14,7 @@ import {
DestroyRef,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule, DOCUMENT } from '@angular/common';
import { DOCUMENT } from '@angular/common';
import { Router } from '@angular/router';
import { fromEvent, Subject } from 'rxjs';
import { debounceTime, filter } from 'rxjs/operators';
@ -25,7 +25,7 @@ import { ErrorScreenErrorCodes } from '../../models';
selector: 'abp-http-error-wrapper',
templateUrl: './http-error-wrapper.component.html',
styleUrls: ['http-error-wrapper.component.scss'],
imports: [CommonModule, LocalizationPipe],
imports: [LocalizationPipe],
})
export class HttpErrorWrapperComponent implements OnInit, AfterViewInit, OnDestroy {
protected readonly destroyRef = inject(DestroyRef);

7
npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts

@ -1,4 +1,3 @@
import { NgClass, NgStyle } from '@angular/common';
import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit, inject } from '@angular/core';
import { combineLatest, Subscription, timer } from 'rxjs';
import { HttpWaitService, RouterWaitService, SubscriptionService } from '@abp/ng.core';
@ -6,12 +5,12 @@ import { HttpWaitService, RouterWaitService, SubscriptionService } from '@abp/ng
@Component({
selector: 'abp-loader-bar',
template: `
<div id="abp-loader-bar" [ngClass]="containerClass" [class.is-loading]="isLoading">
<div id="abp-loader-bar" [class]="containerClass" [class.is-loading]="isLoading">
<div
class="abp-progress"
[class.progressing]="progressLevel"
[style.width.vw]="progressLevel"
[ngStyle]="{
[style]="{
'background-color': color,
'box-shadow': boxShadow,
}"
@ -20,7 +19,7 @@ import { HttpWaitService, RouterWaitService, SubscriptionService } from '@abp/ng
`,
styleUrls: ['./loader-bar.component.scss'],
providers: [SubscriptionService],
imports: [NgClass, NgStyle],
imports: [],
})
export class LoaderBarComponent implements OnDestroy, OnInit {
private cdRef = inject(ChangeDetectorRef);

2
npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.html

@ -10,7 +10,7 @@
<i
class="fa"
aria-hidden="true"
[ngClass]="{
[class]="{
'fa-eye-slash': !fieldTextType,
'fa-eye': fieldTextType
}"

4
npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.ts

@ -1,6 +1,6 @@
import { Component, forwardRef, Input } from '@angular/core';
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import { NgClass } from '@angular/common';
import { AbstractNgModelComponent } from '@abp/ng.core';
import { NgxValidateCoreModule } from '@ngx-validate/core';
@ -10,7 +10,7 @@ import { NgxValidateCoreModule } from '@ngx-validate/core';
*/
@Component({
selector: 'abp-password',
imports: [NgClass, FormsModule, NgxValidateCoreModule],
imports: [FormsModule, NgxValidateCoreModule],
templateUrl: `./password.component.html`,
providers: [
{

18
npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.html

@ -1,19 +1,17 @@
<div class="abp-toast" [ngClass]="severityClass" (click)="tap()">
<div class="abp-toast" [class]="severityClass" (click)="tap()">
<div class="abp-toast-icon">
<i class="bi icon" [ngClass]="iconClass" aria-hidden="true"></i>
<i class="bi icon" [class]="iconClass" aria-hidden="true"></i>
</div>
<div class="abp-toast-content">
@if (toast.options?.closable) {
<button class="abp-toast-close-button" (click)="close()">
<i class="bi bi-x fs-4" aria-hidden="true"></i>
</button>
<button class="abp-toast-close-button" (click)="close()">
<i class="bi bi-x fs-4" aria-hidden="true"></i>
</button>
}
<div class="abp-toast-title">
{{ toast.title | abpLocalization: toast.options?.titleLocalizationParams }}
</div>
<p
class="abp-toast-message"
[innerHTML]="toast.message | abpLocalization: toast.options?.messageLocalizationParams"
></p>
<p class="abp-toast-message"
[innerHTML]="toast.message | abpLocalization: toast.options?.messageLocalizationParams"></p>
</div>
</div>
</div>

3
npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.ts

@ -1,5 +1,4 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { NgClass } from '@angular/common';
import { Toaster } from '../../models/toaster';
import { LocalizationPipe } from '@abp/ng.core';
@ -7,7 +6,7 @@ import { LocalizationPipe } from '@abp/ng.core';
selector: 'abp-toast',
templateUrl: './toast.component.html',
styleUrls: ['./toast.component.scss'],
imports: [NgClass, LocalizationPipe],
imports: [LocalizationPipe],
})
export class ToastComponent implements OnInit {
@Input()

74
templates/app-nolayers/angular/src/app/home/home.component.html

@ -9,14 +9,12 @@
Welcome to the application. This is a startup project based on the ABP framework. For
more information visit abp.io.
</p>
<a (click)="login()" class="px-4 btn btn-primary mb-4" role="button"
><i class="fa fa-sign-in"></i> {{ 'AbpAccount::Login' | abpLocalization }}</a
>
<a (click)="login()" class="px-4 btn btn-primary mb-4" role="button"><i class="fa fa-sign-in"></i> {{
'AbpAccount::Login' | abpLocalization }}</a>
}
<h3>Getting Started</h3>
<ng-container
*ngTemplateOutlet="
<ng-container *ngTemplateOutlet="
startingContentTemplate;
context: {
$implicit: {
@ -26,12 +24,10 @@
label: 'Getting Started'
}
}
"
></ng-container>
"></ng-container>
<h4>Web Application Development Tutorial</h4>
<ng-container
*ngTemplateOutlet="
<ng-container *ngTemplateOutlet="
startingContentTemplate;
context: {
$implicit: {
@ -41,17 +37,12 @@
label: 'Explore Tutorial'
}
}
"
></ng-container>
"></ng-container>
<h4>Customize Lepton Theme</h4>
<p class="text-muted mb-2">Learn how to customize LeptonX Theme as you wish.</p>
<a
href="https://docs.abp.io/en/abp/latest/UI/Angular/Theming"
class="btn btn-primary soft mb-5 mb-xl-0"
target="_blank"
>Customize Lepton</a
>
<a href="https://docs.abp.io/en/abp/latest/UI/Angular/Theming" class="btn btn-primary soft mb-5 mb-xl-0"
target="_blank">Customize Lepton</a>
</div>
<img class="card-bg-image" src="assets/images/getting-started/bg-01.png" />
@ -60,8 +51,7 @@
</div>
<div class="col-xl-3 col-md-6 d-flex">
<div class="row">
<ng-container
*ngTemplateOutlet="
<ng-container *ngTemplateOutlet="
visitLinkTemplate;
context: {
$implicit: {
@ -75,10 +65,8 @@
logo: 'abp-support abp-logo mb-2'
}
}
"
></ng-container>
<ng-container
*ngTemplateOutlet="
"></ng-container>
<ng-container *ngTemplateOutlet="
visitLinkTemplate;
context: {
$implicit: {
@ -92,8 +80,7 @@
logo: 'abp-blog abp-logo mb-2'
}
}
"
></ng-container>
"></ng-container>
</div>
</div>
<div class="col-xl-3 col-md-6 d-flex">
@ -108,17 +95,14 @@
Explore all ABP users' experiences with the ABP Framework, discover articles and videos on
how to use ABP, and join raffles for a chance to win surprise gifts!
</p>
<a class="btn btn-brand soft mb-3" href="https://community.abp.io/" target="_blank"
>Join ABP Community</a
>
<a class="btn btn-brand soft mb-3" href="https://community.abp.io/" target="_blank">Join ABP Community</a>
</div>
<img class="mt-3" src="assets/images/getting-started/img-community.png" />
</div>
</div>
</div>
<div class="row">
<ng-container
*ngTemplateOutlet="
<ng-container *ngTemplateOutlet="
tableTemplate;
context: {
$implicit: {
@ -167,8 +151,7 @@
]
}
}
"
></ng-container>
"></ng-container>
<div class="col-xl-6 col-lg-8 d-flex">
<div class="card">
<div class="card-body d-flex">
@ -181,18 +164,12 @@
understanding of the framework and modern web application development techniques.
</p>
<div class="d-md-flex mb-2 mb-md-0">
<a
href="https://www.amazon.com/gp/product/B097Z2DM8Q"
target="_blank"
class="btn btn-primary soft me-md-2 mb-2 mb-md-0"
>
<a href="https://www.amazon.com/gp/product/B097Z2DM8Q" target="_blank"
class="btn btn-primary soft me-md-2 mb-2 mb-md-0">
Buy on Amazon US
</a>
<a
href="https://www.packtpub.com/product/mastering-abp-framework/9781801079242"
target="_blank"
class="btn btn-primary soft mb-2 mb-md-0"
>
<a href="https://www.packtpub.com/product/mastering-abp-framework/9781801079242" target="_blank"
class="btn btn-primary soft mb-2 mb-md-0">
Buy on PACKT
</a>
</div>
@ -204,8 +181,7 @@
</div>
</div>
</div>
<ng-container
*ngTemplateOutlet="
<ng-container *ngTemplateOutlet="
tableTemplate;
context: {
$implicit: {
@ -243,8 +219,7 @@
]
}
}
"
></ng-container>
"></ng-container>
</div>
<ng-template #startingContentTemplate let-context>
@ -279,10 +254,7 @@
<tr>
<td class="ps-0 d-flex" [class.border-bottom-0]="last">
@if(item.icon){
<div
[ngClass]="item.iconClass"
[style]="item.style ? 'width: 20px; height: 20px' : ''"
>
<div [class]="item.iconClass" [style]="item.style ? 'width: 20px; height: 20px' : ''">
@if(item.iconType === 'image'){
<img [src]="item.icon" class="me-2" />
}@else if(item.iconType === 'icon'){
@ -307,4 +279,4 @@
</div>
</div>
</div>
</ng-template>
</ng-template>

74
templates/app/angular/src/app/home/home.component.html

@ -9,14 +9,12 @@
<p class="lead text-muted mb-2">
{{ '::LongWelcomeMessage' | abpLocalization }}
</p>
<a (click)="login()" class="px-4 btn btn-primary mb-4" role="button"
><i class="fa fa-sign-in"></i> {{ 'AbpAccount::Login' | abpLocalization }}</a
>
<a (click)="login()" class="px-4 btn btn-primary mb-4" role="button"><i class="fa fa-sign-in"></i> {{
'AbpAccount::Login' | abpLocalization }}</a>
}
<h3>Getting Started</h3>
<ng-container
*ngTemplateOutlet="
<ng-container *ngTemplateOutlet="
startingContentTemplate;
context: {
$implicit: {
@ -26,12 +24,10 @@
label: 'Getting Started'
}
}
"
></ng-container>
"></ng-container>
<h4>Web Application Development Tutorial</h4>
<ng-container
*ngTemplateOutlet="
<ng-container *ngTemplateOutlet="
startingContentTemplate;
context: {
$implicit: {
@ -41,17 +37,12 @@
label: 'Explore Tutorial'
}
}
"
></ng-container>
"></ng-container>
<h4>Customize Lepton Theme</h4>
<p class="text-muted mb-2">Learn how to customize LeptonX Theme as you wish.</p>
<a
href="https://abp.io/docs/latest/framework/ui/angular/theming"
class="btn btn-primary soft mb-5 mb-xl-0"
target="_blank"
>Customize Lepton</a
>
<a href="https://abp.io/docs/latest/framework/ui/angular/theming" class="btn btn-primary soft mb-5 mb-xl-0"
target="_blank">Customize Lepton</a>
</div>
<img class="card-bg-image" src="assets/images/getting-started/bg-01.png" />
@ -60,8 +51,7 @@
</div>
<div class="col-xl-3 col-md-6 d-flex">
<div class="row">
<ng-container
*ngTemplateOutlet="
<ng-container *ngTemplateOutlet="
visitLinkTemplate;
context: {
$implicit: {
@ -75,10 +65,8 @@
logo: 'abp-support abp-logo mb-2'
}
}
"
></ng-container>
<ng-container
*ngTemplateOutlet="
"></ng-container>
<ng-container *ngTemplateOutlet="
visitLinkTemplate;
context: {
$implicit: {
@ -92,8 +80,7 @@
logo: 'abp-blog abp-logo mb-2'
}
}
"
></ng-container>
"></ng-container>
</div>
</div>
<div class="col-xl-3 col-md-6 d-flex">
@ -108,17 +95,14 @@
Explore all ABP users' experiences with the ABP Framework, discover articles and videos on
how to use ABP, and join raffles for a chance to win surprise gifts!
</p>
<a class="btn btn-brand soft mb-3" href="https://abp.io/community/" target="_blank"
>Join ABP Community</a
>
<a class="btn btn-brand soft mb-3" href="https://abp.io/community/" target="_blank">Join ABP Community</a>
</div>
<img class="mt-3" src="assets/images/getting-started/img-community.png" />
</div>
</div>
</div>
<div class="row">
<ng-container
*ngTemplateOutlet="
<ng-container *ngTemplateOutlet="
tableTemplate;
context: {
$implicit: {
@ -167,8 +151,7 @@
]
}
}
"
></ng-container>
"></ng-container>
<div class="col-xl-6 col-lg-8 d-flex">
<div class="card">
<div class="card-body d-flex">
@ -181,18 +164,12 @@
understanding of the framework and modern web application development techniques.
</p>
<div class="d-md-flex mb-2 mb-md-0">
<a
href="https://www.amazon.com/gp/product/B097Z2DM8Q"
target="_blank"
class="btn btn-primary soft me-md-2 mb-2 mb-md-0"
>
<a href="https://www.amazon.com/gp/product/B097Z2DM8Q" target="_blank"
class="btn btn-primary soft me-md-2 mb-2 mb-md-0">
Buy on Amazon US
</a>
<a
href="https://www.packtpub.com/product/mastering-abp-framework/9781801079242"
target="_blank"
class="btn btn-primary soft mb-2 mb-md-0"
>
<a href="https://www.packtpub.com/product/mastering-abp-framework/9781801079242" target="_blank"
class="btn btn-primary soft mb-2 mb-md-0">
Buy on PACKT
</a>
</div>
@ -204,8 +181,7 @@
</div>
</div>
</div>
<ng-container
*ngTemplateOutlet="
<ng-container *ngTemplateOutlet="
tableTemplate;
context: {
$implicit: {
@ -243,8 +219,7 @@
]
}
}
"
></ng-container>
"></ng-container>
</div>
<ng-template #startingContentTemplate let-context>
@ -279,10 +254,7 @@
<tr>
<td class="ps-0 d-flex" [class.border-bottom-0]="last">
@if(item.icon){
<div
[ngClass]="item.iconClass"
[style]="item.style ? 'width: 20px; height: 20px' : ''"
>
<div [class]="item.iconClass" [style]="item.style ? 'width: 20px; height: 20px' : ''">
@if(item.iconType === 'image'){
<img [src]="item.icon" class="me-2" />
}@else if(item.iconType === 'icon'){
@ -307,4 +279,4 @@
</div>
</div>
</div>
</ng-template>
</ng-template>
Loading…
Cancel
Save