mirror of https://github.com/abpframework/abp.git
committed by
GitHub
57 changed files with 1228 additions and 1052 deletions
@ -1,119 +1,202 @@ |
|||
@if (isBrowser) { |
|||
<ngx-datatable #table default [rows]="data" [count]="recordsTotal" [list]="list" |
|||
[selectionType]="selectable ? _selectionType : undefined" (activate)="tableActivate.emit($event)" |
|||
(select)="onSelect($event)" [selected]="selected" (scroll)="onScroll($event)" [scrollbarV]="infiniteScroll" |
|||
[style.height]="getTableHeight()" [loadingIndicator]="infiniteScroll && isLoading" |
|||
[footerHeight]="infiniteScroll ? false : 50"> |
|||
@if (effectiveRowDetailTemplate) { |
|||
<ngx-datatable-row-detail [rowHeight]="effectiveRowDetailHeight"> |
|||
<ng-template let-row="row" let-expanded="expanded" ngx-datatable-row-detail-template> |
|||
<ng-container |
|||
*ngTemplateOutlet="effectiveRowDetailTemplate; context: { row: row, expanded: expanded }" /> |
|||
</ng-template> |
|||
</ngx-datatable-row-detail> |
|||
<ngx-datatable |
|||
#table |
|||
default |
|||
[rows]="data" |
|||
[count]="recordsTotal()" |
|||
[list]="list()" |
|||
[selectionType]="selectable() ? selectionType() : undefined" |
|||
(activate)="tableActivate.emit($event)" |
|||
(select)="onSelect($event)" |
|||
[selected]="selected()" |
|||
(scroll)="onScroll($event)" |
|||
[scrollbarV]="infiniteScroll()" |
|||
[style.height]="getTableHeight()" |
|||
[loadingIndicator]="infiniteScroll() && isLoading()" |
|||
[footerHeight]="infiniteScroll() ? false : 50" |
|||
> |
|||
@if (effectiveRowDetailTemplate) { |
|||
<ngx-datatable-row-detail [rowHeight]="effectiveRowDetailHeight"> |
|||
<ng-template let-row="row" let-expanded="expanded" ngx-datatable-row-detail-template> |
|||
<ng-container |
|||
*ngTemplateOutlet=" |
|||
effectiveRowDetailTemplate; |
|||
context: { row: row, expanded: expanded } |
|||
" |
|||
/> |
|||
</ng-template> |
|||
</ngx-datatable-row-detail> |
|||
|
|||
<ngx-datatable-column [width]="50" [resizeable]="false" [sortable]="false" [draggable]="false" |
|||
[canAutoResize]="false"> |
|||
<ng-template let-row="row" let-expanded="expanded" ngx-datatable-cell-template> |
|||
<button type="button" class="btn btn-link text-decoration-none text-muted p-0" |
|||
[attr.aria-label]="expanded ? 'Collapse' : 'Expand'" (click)="toggleExpandRow(row)"> |
|||
<i class="fa" [class.fa-chevron-down]="!expanded" [class.fa-chevron-up]="expanded"></i> |
|||
</button> |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
} |
|||
@if(selectable) { |
|||
<ngx-datatable-column [width]="50" [sortable]="false" [canAutoResize]="false" [draggable]="false" |
|||
[resizeable]="false"> |
|||
|
|||
<ng-template ngx-datatable-header-template let-value="value" let-allRowsSelected="allRowsSelected" |
|||
let-selectFn="selectFn"> |
|||
@if (_selectionType !== 'single') { |
|||
<div class="form-check"> |
|||
<input class="form-check-input table-check" type="checkbox" [checked]="allRowsSelected" |
|||
(change)="selectFn(!allRowsSelected)" /> |
|||
</div> |
|||
} |
|||
</ng-template> |
|||
|
|||
<ng-template ngx-datatable-cell-template let-value="value" let-row="row" let-isSelected="isSelected" |
|||
let-onCheckboxChangeFn="onCheckboxChangeFn"> |
|||
@if(_selectionType === 'single') { |
|||
<div class="h-100 form-check form-check-sm form-check-custom form-check-solid"> |
|||
<input class="form-check-input" type="radio" [checked]="isSelected" (change)="onCheckboxChangeFn($event)" /> |
|||
</div> |
|||
} |
|||
@if (_selectionType !== 'single') { |
|||
<div class="h-100 form-check form-check-sm form-check-custom form-check-solid"> |
|||
<input class="form-check-input" type="checkbox" [checked]="isSelected" (change)="onCheckboxChangeFn($event)" /> |
|||
</div> |
|||
} |
|||
</ng-template> |
|||
<ngx-datatable-column |
|||
[width]="50" |
|||
[resizeable]="false" |
|||
[sortable]="false" |
|||
[draggable]="false" |
|||
[canAutoResize]="false" |
|||
> |
|||
<ng-template let-row="row" let-expanded="expanded" ngx-datatable-cell-template> |
|||
<button |
|||
type="button" |
|||
class="btn btn-link text-decoration-none text-muted p-0" |
|||
[attr.aria-label]="expanded ? 'Collapse' : 'Expand'" |
|||
(click)="toggleExpandRow(row)" |
|||
> |
|||
<i class="fa" [class.fa-chevron-down]="!expanded" [class.fa-chevron-up]="expanded"></i> |
|||
</button> |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
} |
|||
@if (selectable()) { |
|||
<ngx-datatable-column |
|||
[width]="50" |
|||
[sortable]="false" |
|||
[canAutoResize]="false" |
|||
[draggable]="false" |
|||
[resizeable]="false" |
|||
> |
|||
<ng-template |
|||
ngx-datatable-header-template |
|||
let-value="value" |
|||
let-allRowsSelected="allRowsSelected" |
|||
let-selectFn="selectFn" |
|||
> |
|||
@if (selectionType() !== 'single') { |
|||
<div class="form-check"> |
|||
<input |
|||
class="form-check-input table-check" |
|||
type="checkbox" |
|||
[checked]="allRowsSelected" |
|||
(change)="selectFn(!allRowsSelected)" |
|||
/> |
|||
</div> |
|||
} |
|||
</ng-template> |
|||
|
|||
</ngx-datatable-column> |
|||
} |
|||
@if (actionsTemplate || (actionList.length && hasAtLeastOnePermittedAction)) { |
|||
<ngx-datatable-column [name]="actionsText | abpLocalization" [maxWidth]="_actionsColumnWidth() ?? undefined" |
|||
[width]="_actionsColumnWidth() ?? 200" [canAutoResize]="!_actionsColumnWidth()" [sortable]="false"> |
|||
<ng-template let-row="row" let-i="rowIndex" ngx-datatable-cell-template> |
|||
<ng-container |
|||
*ngTemplateOutlet="actionsTemplate || gridActions; context: { $implicit: row, index: i }"></ng-container> |
|||
<ng-template #gridActions> |
|||
@if (isVisibleActions(row)) { |
|||
<abp-grid-actions [index]="i" [record]="row" text="AbpUi::Actions"></abp-grid-actions> |
|||
} |
|||
</ng-template> |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
} |
|||
@for (prop of propList; track prop.name; let i = $index) { |
|||
<ngx-datatable-column *abpVisible="prop.columnVisible(getInjected)" [width]="columnWidths[i] ?? 200" |
|||
[canAutoResize]="!columnWidths[i]" |
|||
[name]="(prop.isExtra ? '::' + prop.displayName : prop.displayName) | abpLocalization" [prop]="prop.name" |
|||
[sortable]="prop.sortable"> |
|||
<ng-template ngx-datatable-header-template let-column="column" let-sortFn="sortFn"> |
|||
@if (prop.tooltip) { |
|||
<span [ngbTooltip]="prop.tooltip.text | abpLocalization" [placement]="prop.tooltip.placement || 'auto'" |
|||
container="body" [class.pointer]="prop.sortable" (click)="prop.sortable && sortFn(column)"> |
|||
{{ column.name }} <i class="fa fa-info-circle" aria-hidden="true"></i> |
|||
</span> |
|||
} @else { |
|||
<span [class.pointer]="prop.sortable" (click)="prop.sortable && sortFn(column)"> |
|||
{{ column.name }} |
|||
</span> |
|||
} |
|||
</ng-template> |
|||
<ng-template let-row="row" let-i="index" ngx-datatable-cell-template> |
|||
<ng-container *abpPermission="prop.permission; runChangeDetection: false"> |
|||
<ng-container *abpVisible="row['_' + prop.name]?.visible"> |
|||
@if (!row['_' + prop.name].component) { |
|||
@if (prop.type === 'datetime' || prop.type === 'date' || prop.type === 'time') { |
|||
<div [innerHTML]=" |
|||
!prop.isExtra |
|||
? (row['_' + prop.name]?.value | async | abpUtcToLocal:prop.type) |
|||
: ('::' + (row['_' + prop.name]?.value | async | abpUtcToLocal:prop.type) | abpLocalization) |
|||
" (click)=" |
|||
prop.action && prop.action({ getInjected: getInjected, record: row, index: i }) |
|||
" [class]="entityPropTypeClasses[prop.type]" [class.pointer]="prop.action"></div> |
|||
} @else { |
|||
<div [innerHTML]=" |
|||
!prop.isExtra |
|||
? (row['_' + prop.name]?.value | async) |
|||
: ('::' + (row['_' + prop.name]?.value | async) | abpLocalization) |
|||
" (click)=" |
|||
prop.action && prop.action({ getInjected: getInjected, record: row, index: i }) |
|||
" [class]="entityPropTypeClasses[prop.type]" [class.pointer]="prop.action"></div> |
|||
<ng-template |
|||
ngx-datatable-cell-template |
|||
let-value="value" |
|||
let-row="row" |
|||
let-isSelected="isSelected" |
|||
let-onCheckboxChangeFn="onCheckboxChangeFn" |
|||
> |
|||
@if (selectionType() === 'single') { |
|||
<div class="h-100 form-check form-check-sm form-check-custom form-check-solid"> |
|||
<input |
|||
class="form-check-input" |
|||
type="radio" |
|||
[checked]="isSelected" |
|||
(change)="onCheckboxChangeFn($event)" |
|||
/> |
|||
</div> |
|||
} |
|||
@if (selectionType() !== 'single') { |
|||
<div class="h-100 form-check form-check-sm form-check-custom form-check-solid"> |
|||
<input |
|||
class="form-check-input" |
|||
type="checkbox" |
|||
[checked]="isSelected" |
|||
(change)="onCheckboxChangeFn($event)" |
|||
/> |
|||
</div> |
|||
} |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
} |
|||
@if (actionsTemplate() || (actionList.length && hasAtLeastOnePermittedAction)) { |
|||
<ngx-datatable-column |
|||
[name]="actionsText() | abpLocalization" |
|||
[maxWidth]="_actionsColumnWidth() ?? undefined" |
|||
[width]="_actionsColumnWidth() ?? 200" |
|||
[canAutoResize]="!_actionsColumnWidth()" |
|||
[sortable]="false" |
|||
> |
|||
<ng-template let-row="row" let-i="rowIndex" ngx-datatable-cell-template> |
|||
<ng-container |
|||
*ngTemplateOutlet=" |
|||
actionsTemplate() || gridActions; |
|||
context: { $implicit: row, index: i } |
|||
" |
|||
></ng-container> |
|||
<ng-template #gridActions> |
|||
@if (isVisibleActions(row)) { |
|||
<abp-grid-actions [index]="i" [record]="row" text="AbpUi::Actions"></abp-grid-actions> |
|||
} |
|||
</ng-template> |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
} |
|||
@for (prop of propList; track prop.name; let i = $index) { |
|||
<ngx-datatable-column |
|||
*abpVisible="prop.columnVisible(getInjected)" |
|||
[width]="columnWidths()[i] ?? 200" |
|||
[canAutoResize]="!columnWidths()[i]" |
|||
[name]="(prop.isExtra ? '::' + prop.displayName : prop.displayName) | abpLocalization" |
|||
[prop]="prop.name" |
|||
[sortable]="prop.sortable" |
|||
> |
|||
<ng-template ngx-datatable-header-template let-column="column" let-sortFn="sortFn"> |
|||
@if (prop.tooltip) { |
|||
<span |
|||
[ngbTooltip]="prop.tooltip.text | abpLocalization" |
|||
[placement]="prop.tooltip.placement || 'auto'" |
|||
container="body" |
|||
[class.pointer]="prop.sortable" |
|||
(click)="prop.sortable && sortFn(column)" |
|||
> |
|||
{{ column.name }} <i class="fa fa-info-circle" aria-hidden="true"></i> |
|||
</span> |
|||
} @else { |
|||
<ng-container *ngComponentOutlet=" |
|||
row['_' + prop.name].component; |
|||
injector: row['_' + prop.name].injector |
|||
"></ng-container> |
|||
<span [class.pointer]="prop.sortable" (click)="prop.sortable && sortFn(column)"> |
|||
{{ column.name }} |
|||
</span> |
|||
} |
|||
</ng-container> |
|||
</ng-container> |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
} |
|||
</ngx-datatable> |
|||
} |
|||
</ng-template> |
|||
<ng-template let-row="row" let-i="index" ngx-datatable-cell-template> |
|||
<ng-container *abpPermission="prop.permission; runChangeDetection: false"> |
|||
<ng-container *abpVisible="row['_' + prop.name]?.visible"> |
|||
@if (!row['_' + prop.name].component) { |
|||
@if (prop.type === 'datetime' || prop.type === 'date' || prop.type === 'time') { |
|||
<div |
|||
[innerHTML]=" |
|||
!prop.isExtra |
|||
? (row['_' + prop.name]?.value | async | abpUtcToLocal: prop.type) |
|||
: ('::' + (row['_' + prop.name]?.value | async | abpUtcToLocal: prop.type) |
|||
| abpLocalization) |
|||
" |
|||
(click)=" |
|||
prop.action && |
|||
prop.action({ getInjected: getInjected, record: row, index: i }) |
|||
" |
|||
[class]="entityPropTypeClasses[prop.type]" |
|||
[class.pointer]="prop.action" |
|||
></div> |
|||
} @else { |
|||
<div |
|||
[innerHTML]=" |
|||
!prop.isExtra |
|||
? (row['_' + prop.name]?.value | async) |
|||
: ('::' + (row['_' + prop.name]?.value | async) | abpLocalization) |
|||
" |
|||
(click)=" |
|||
prop.action && |
|||
prop.action({ getInjected: getInjected, record: row, index: i }) |
|||
" |
|||
[class]="entityPropTypeClasses[prop.type]" |
|||
[class.pointer]="prop.action" |
|||
></div> |
|||
} |
|||
} @else { |
|||
<ng-container |
|||
*ngComponentOutlet=" |
|||
row['_' + prop.name].component; |
|||
injector: row['_' + prop.name].injector |
|||
" |
|||
></ng-container> |
|||
} |
|||
</ng-container> |
|||
</ng-container> |
|||
</ng-template> |
|||
</ngx-datatable-column> |
|||
} |
|||
</ngx-datatable> |
|||
} |
|||
|
|||
@ -1,13 +1,13 @@ |
|||
import { Component, HostBinding, Input } from '@angular/core'; |
|||
import { Component, HostBinding, input } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'abp-card-body', |
|||
template: ` <div [class]="cardBodyClass" [style]="cardBodyStyle">
|
|||
template: ` <div [class]="cardBodyClass()" [style]="cardBodyStyle()">
|
|||
<ng-content></ng-content> |
|||
</div>`,
|
|||
}) |
|||
export class CardBodyComponent { |
|||
@HostBinding('class') componentClass = 'card-body'; |
|||
@Input() cardBodyClass: string; |
|||
@Input() cardBodyStyle: string; |
|||
readonly cardBodyClass = input<string>(undefined); |
|||
readonly cardBodyStyle = input<string>(undefined); |
|||
} |
|||
|
|||
@ -1,14 +1,14 @@ |
|||
import { Component, Input } from '@angular/core'; |
|||
import { Component, input } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'abp-card', |
|||
template: ` <div class="card" [class]="cardClass" [style]="cardStyle">
|
|||
template: ` <div class="card" [class]="cardClass()" [style]="cardStyle()">
|
|||
<ng-content></ng-content> |
|||
</div>`,
|
|||
imports: [], |
|||
}) |
|||
export class CardComponent { |
|||
@Input() cardClass: string; |
|||
readonly cardClass = input<string>(undefined); |
|||
|
|||
@Input() cardStyle: string; |
|||
readonly cardStyle = input<string>(undefined); |
|||
} |
|||
|
|||
@ -1,47 +1,48 @@ |
|||
import { |
|||
AfterViewInit, |
|||
ChangeDetectorRef, |
|||
Directive, |
|||
ElementRef, |
|||
HostBinding, |
|||
Input, |
|||
inject |
|||
import { |
|||
AfterViewInit, |
|||
ChangeDetectorRef, |
|||
computed, |
|||
Directive, |
|||
ElementRef, |
|||
inject, |
|||
input, |
|||
signal |
|||
} from '@angular/core'; |
|||
|
|||
@Directive({ |
|||
selector: '[abpEllipsis]', |
|||
host: { |
|||
'[title]': 'effectiveTitle()', |
|||
'[class.abp-ellipsis-inline]': 'inlineClass()', |
|||
'[class.abp-ellipsis]': 'ellipsisClass()', |
|||
'[style.max-width]': 'maxWidth()' |
|||
} |
|||
}) |
|||
export class EllipsisDirective implements AfterViewInit { |
|||
private cdRef = inject(ChangeDetectorRef); |
|||
private elRef = inject(ElementRef); |
|||
|
|||
@Input('abpEllipsis') |
|||
width?: string; |
|||
readonly width = input<string | undefined>(undefined, { alias: 'abpEllipsis' }); |
|||
readonly title = input<string | undefined>(undefined); |
|||
readonly enabled = input(true, { alias: 'abpEllipsisEnabled' }); |
|||
|
|||
@HostBinding('title') |
|||
@Input() |
|||
title?: string; |
|||
private readonly autoTitle = signal<string | undefined>(undefined); |
|||
|
|||
@Input('abpEllipsisEnabled') |
|||
enabled = true; |
|||
protected readonly effectiveTitle = computed(() => this.title() || this.autoTitle()); |
|||
|
|||
@HostBinding('class.abp-ellipsis-inline') |
|||
get inlineClass() { |
|||
return this.enabled && this.width; |
|||
} |
|||
protected readonly inlineClass = computed(() => this.enabled() && !!this.width()); |
|||
|
|||
@HostBinding('class.abp-ellipsis') |
|||
get class() { |
|||
return this.enabled && !this.width; |
|||
} |
|||
protected readonly ellipsisClass = computed(() => this.enabled() && !this.width()); |
|||
|
|||
@HostBinding('style.max-width') |
|||
get maxWidth() { |
|||
return this.enabled && this.width ? this.width || '170px' : undefined; |
|||
} |
|||
protected readonly maxWidth = computed(() => { |
|||
const width = this.width(); |
|||
return this.enabled() && width ? width || '170px' : undefined; |
|||
}); |
|||
|
|||
ngAfterViewInit() { |
|||
this.title = this.title || (this.elRef.nativeElement as HTMLElement).innerText; |
|||
this.cdRef.detectChanges(); |
|||
if (!this.title()) { |
|||
this.autoTitle.set((this.elRef.nativeElement as HTMLElement).innerText); |
|||
this.cdRef.detectChanges(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue