migrate control flow
This commit is contained in:
parent
0b64044f57
commit
f60ea513ac
@ -6,7 +6,7 @@ module.exports = {
|
||||
globals: {
|
||||
NodeJS: true,
|
||||
},
|
||||
ignorePatterns: ['!**/*'],
|
||||
ignorePatterns: ['!**/*', 'jest.config.ts'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts'],
|
||||
|
||||
@ -1,30 +1,38 @@
|
||||
<section class="dialog">
|
||||
<div [class.warn]="isDeleteAction" [innerHTML]="config.title" class="dialog-header heading-l"></div>
|
||||
|
||||
<div *ngIf="showToast && config.toastMessage" class="inline-dialog-toast toast-error">
|
||||
@if (showToast && config.toastMessage) {
|
||||
<div class="inline-dialog-toast toast-error">
|
||||
<div [translate]="config.toastMessage"></div>
|
||||
<a (click)="showToast = false" class="toast-close-button">
|
||||
<mat-icon svgIcon="iqser:close"></mat-icon>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="dialog-content">
|
||||
<p [class.heading]="isDeleteAction" [innerHTML]="config.question" class="mt-0 mb-8"></p>
|
||||
<p *ngIf="config.details" [innerHTML]="config.details" class="mt-0"></p>
|
||||
@if (config.details) {
|
||||
<p [innerHTML]="config.details" class="mt-0"></p>
|
||||
}
|
||||
|
||||
<div *ngIf="config.requireInput" class="iqser-input-group required w-300 mt-24">
|
||||
@if (config.requireInput) {
|
||||
<div class="iqser-input-group required w-300 mt-24">
|
||||
<label>{{ inputLabel }}</label>
|
||||
<input [(ngModel)]="inputValue" id="confirmation-input" />
|
||||
</div>
|
||||
}
|
||||
|
||||
<div *ngIf="config.checkboxes.length > 0" class="mt-24 checkboxes-wrapper">
|
||||
<ng-container *ngFor="let checkbox of config.checkboxes">
|
||||
@if (config.checkboxes.length > 0) {
|
||||
<div class="mt-24 checkboxes-wrapper">
|
||||
@for (checkbox of config.checkboxes; track checkbox) {
|
||||
<mat-checkbox [(ngModel)]="checkbox.value" [class.error]="!checkbox.value && showToast" color="primary">
|
||||
{{ checkbox.label | translate: config.translateParams }}
|
||||
</mat-checkbox>
|
||||
<ng-container *ngTemplateOutlet="checkbox.extraContent; context: { data: checkbox.extraContentData }"></ng-container>
|
||||
</ng-container>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
@ -36,21 +44,26 @@
|
||||
buttonId="confirm"
|
||||
></iqser-icon-button>
|
||||
|
||||
@if (config.alternativeConfirmationText) {
|
||||
<iqser-icon-button
|
||||
(action)="confirm(confirmOptions.CONFIRM_WITH_ACTION)"
|
||||
*ngIf="config.alternativeConfirmationText"
|
||||
[disabled]="config.requireInput && confirmationDoesNotMatch()"
|
||||
[label]="config.alternativeConfirmationText"
|
||||
[type]="iconButtonTypes.primary"
|
||||
></iqser-icon-button>
|
||||
}
|
||||
|
||||
<div (click)="confirm(confirmOptions.DISCARD_CHANGES)" *ngIf="config.discardChangesText" class="all-caps-label cancel">
|
||||
@if (config.discardChangesText) {
|
||||
<div (click)="confirm(confirmOptions.DISCARD_CHANGES)" class="all-caps-label cancel">
|
||||
{{ config.discardChangesText }}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div (click)="deny()" *ngIf="!config.discardChangesText" class="all-caps-label cancel">
|
||||
@if (!config.discardChangesText) {
|
||||
<div (click)="deny()" class="all-caps-label cancel">
|
||||
{{ config.denyText }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<iqser-circle-button class="dialog-close" icon="iqser:close" mat-dialog-close></iqser-circle-button>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { NgForOf, NgIf, NgTemplateOutlet } from '@angular/common';
|
||||
import { NgTemplateOutlet } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, HostListener, inject, TemplateRef } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@ -72,10 +72,8 @@ function getConfig(options?: IConfirmationDialogData): InternalConfirmationDialo
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [
|
||||
NgIf,
|
||||
MatIconModule,
|
||||
FormsModule,
|
||||
NgForOf,
|
||||
MatCheckboxModule,
|
||||
TranslateModule,
|
||||
NgTemplateOutlet,
|
||||
|
||||
@ -6,7 +6,9 @@
|
||||
}"
|
||||
class="empty-state"
|
||||
>
|
||||
<mat-icon *ngIf="icon" [svgIcon]="icon"></mat-icon>
|
||||
@if (icon) {
|
||||
<mat-icon [svgIcon]="icon"></mat-icon>
|
||||
}
|
||||
|
||||
<div class="ng-content-wrapper heading-l">
|
||||
<ng-content></ng-content>
|
||||
@ -14,13 +16,14 @@
|
||||
|
||||
<div [innerHTML]="text" class="heading-l"></div>
|
||||
|
||||
@if (showButton) {
|
||||
<iqser-icon-button
|
||||
(action)="action.emit()"
|
||||
*ngIf="showButton"
|
||||
[buttonId]="buttonId"
|
||||
[icon]="buttonIcon"
|
||||
[attr.help-mode-key]="helpModeKey"
|
||||
[label]="buttonLabel"
|
||||
[type]="iconButtonTypes.primary"
|
||||
></iqser-icon-button>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { IconButtonComponent, IconButtonTypes } from '../buttons';
|
||||
import { randomString } from '../utils';
|
||||
import { NgIf, NgStyle } from '@angular/common';
|
||||
import { NgStyle } from '@angular/common';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
@Component({
|
||||
@ -10,7 +10,7 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
styleUrls: ['./empty-state.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [NgStyle, MatIconModule, NgIf, IconButtonComponent],
|
||||
imports: [NgStyle, MatIconModule, IconButtonComponent],
|
||||
})
|
||||
export class EmptyStateComponent implements OnInit {
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
<div
|
||||
*ngIf="errorService.connectionStatus$ | async as status"
|
||||
[@animateOpenClose]="status"
|
||||
[ngClass]="status"
|
||||
class="indicator flex-align-items-center"
|
||||
>
|
||||
@if (errorService.connectionStatus$ | async; as status) {
|
||||
<div [@animateOpenClose]="status" [ngClass]="status" class="indicator flex-align-items-center">
|
||||
<span [translate]="connectionStatusTranslations[status]"></span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
<ng-container *ngIf="errorService.error$ | async as error">
|
||||
@if (errorService.error$ | async; as error) {
|
||||
<section class="full-page-section"></section>
|
||||
|
||||
<section class="full-page-content flex-align-items-center">
|
||||
<mat-icon svgIcon="iqser:failure"></mat-icon>
|
||||
|
||||
<div [translate]="errorTitle(error)" class="heading-l mt-24"></div>
|
||||
|
||||
<div *ngIf="error.message" class="mt-16 error">{{ error.message }}</div>
|
||||
|
||||
@if (error.message) {
|
||||
<div class="mt-16 error">{{ error.message }}</div>
|
||||
}
|
||||
<iqser-icon-button
|
||||
(action)="action(error)"
|
||||
[icon]="actionIcon(error)"
|
||||
@ -16,4 +14,4 @@
|
||||
class="mt-20"
|
||||
></iqser-icon-button>
|
||||
</section>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<ng-container *ngIf="primaryFilterGroup$ | async as primaryGroup">
|
||||
<div *ngIf="primaryGroup.filterceptionPlaceholder" class="input-wrapper">
|
||||
@if (primaryFilterGroup$ | async; as primaryGroup) {
|
||||
@if (primaryGroup.filterceptionPlaceholder) {
|
||||
<div class="input-wrapper">
|
||||
<iqser-input-with-action
|
||||
[(value)]="searchService.searchValue"
|
||||
[id]="'filterception-' + primaryGroup.slug"
|
||||
@ -7,12 +8,12 @@
|
||||
[width]="'full'"
|
||||
></iqser-input-with-action>
|
||||
</div>
|
||||
|
||||
}
|
||||
<ng-container *ngTemplateOutlet="filterHeader"></ng-container>
|
||||
|
||||
<div *ngIf="primaryFilters$ | async as filters" class="filter-content">
|
||||
@if (primaryFilters$ | async; as filters) {
|
||||
<div class="filter-content">
|
||||
@for (filter of filters; track filter) {
|
||||
<ng-container
|
||||
*ngFor="let filter of filters"
|
||||
[ngTemplateOutletContext]="{
|
||||
filter: filter,
|
||||
filterGroup: primaryGroup,
|
||||
@ -20,15 +21,16 @@
|
||||
}"
|
||||
[ngTemplateOutlet]="defaultFilterTemplate"
|
||||
></ng-container>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div *ngIf="secondaryFilterGroup$ | async as secondaryGroup" class="filter-options">
|
||||
}
|
||||
@if (secondaryFilterGroup$ | async; as secondaryGroup) {
|
||||
<div class="filter-options">
|
||||
<div class="filter-menu-options">
|
||||
<div class="all-caps-label" translate="filter-menu.filter-options"></div>
|
||||
</div>
|
||||
|
||||
@for (filter of secondaryGroup.filters; track filter) {
|
||||
<ng-container
|
||||
*ngFor="let filter of secondaryGroup.filters"
|
||||
[ngTemplateOutletContext]="{
|
||||
filter: filter,
|
||||
filterGroup: secondaryGroup,
|
||||
@ -36,8 +38,10 @@
|
||||
}"
|
||||
[ngTemplateOutlet]="defaultFilterTemplate"
|
||||
></ng-container>
|
||||
}
|
||||
</div>
|
||||
</ng-container>
|
||||
}
|
||||
}
|
||||
|
||||
<ng-template #defaultFilterLabelTemplate let-filter="filter">
|
||||
{{ filter?.label }}
|
||||
@ -45,30 +49,46 @@
|
||||
|
||||
<!--TODO: move to separate component-->
|
||||
<ng-template #filterHeader>
|
||||
<div *ngIf="primaryFilterGroup$ | async as primaryGroup" class="filter-menu-header">
|
||||
@if (primaryFilterGroup$ | async; as primaryGroup) {
|
||||
<div class="filter-menu-header">
|
||||
<div [translateParams]="{ count: primaryGroup.filters.length }" [translate]="primaryFiltersLabel" class="all-caps-label"></div>
|
||||
<div class="actions">
|
||||
@if (!primaryGroup.singleSelect) {
|
||||
<div
|
||||
(click)="activatePrimaryFilters()"
|
||||
*ngIf="!primaryGroup.singleSelect"
|
||||
class="all-caps-label primary pointer"
|
||||
iqserStopPropagation
|
||||
translate="actions.all"
|
||||
></div>
|
||||
<div (click)="deactivateFilters()" class="all-caps-label primary pointer" iqserStopPropagation translate="actions.none"></div>
|
||||
}
|
||||
<div
|
||||
(click)="deactivateFilters()"
|
||||
class="all-caps-label primary pointer"
|
||||
iqserStopPropagation
|
||||
translate="actions.none"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</ng-template>
|
||||
|
||||
<!--TODO: move to separate component-->
|
||||
<ng-template #defaultFilterTemplate let-atLeastOneIsExpandable="atLeastOneIsExpandable" let-filter="filter" let-filterGroup="filterGroup">
|
||||
<div (click)="toggleFilterExpanded(filter)" class="mat-mdc-menu-item flex" iqserStopPropagation>
|
||||
<div *ngIf="filter.children?.length > 0" class="arrow-wrapper">
|
||||
<mat-icon *ngIf="filter.expanded" color="accent" svgIcon="iqser:arrow-down"></mat-icon>
|
||||
<mat-icon *ngIf="!filter.expanded" color="accent" svgIcon="iqser:arrow-right"></mat-icon>
|
||||
@if (filter.children?.length > 0) {
|
||||
<div class="arrow-wrapper">
|
||||
@if (filter.expanded) {
|
||||
<mat-icon color="accent" svgIcon="iqser:arrow-down"></mat-icon>
|
||||
}
|
||||
@if (!filter.expanded) {
|
||||
<mat-icon color="accent" svgIcon="iqser:arrow-right"></mat-icon>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div *ngIf="atLeastOneIsExpandable && filter.children?.length === 0" class="arrow-wrapper spacer"> </div>
|
||||
@if (atLeastOneIsExpandable && filter.children?.length === 0) {
|
||||
<div class="arrow-wrapper spacer"> </div>
|
||||
}
|
||||
|
||||
<mat-checkbox
|
||||
(click)="filterCheckboxClicked(filter, filterGroup)"
|
||||
@ -87,16 +107,23 @@
|
||||
<ng-container [ngTemplateOutletContext]="{ filter: filter }" [ngTemplateOutlet]="actionsTemplate"></ng-container>
|
||||
</div>
|
||||
|
||||
<div *ngIf="filter.children?.length && filter.expanded">
|
||||
<div *ngFor="let child of filter.children" class="padding-left mat-mdc-menu-item" iqserStopPropagation>
|
||||
<mat-checkbox (click)="filterCheckboxClicked(child, filterGroup, filter)" [checked]="child.checked" iqserStopPropagation>
|
||||
@if (filter.children?.length && filter.expanded) {
|
||||
<div>
|
||||
@for (child of filter.children; track child) {
|
||||
<div class="padding-left mat-mdc-menu-item" iqserStopPropagation>
|
||||
<mat-checkbox
|
||||
(click)="filterCheckboxClicked(child, filterGroup, filter)"
|
||||
[checked]="child.checked"
|
||||
iqserStopPropagation
|
||||
>
|
||||
<ng-container
|
||||
[ngTemplateOutletContext]="{ filter: child }"
|
||||
[ngTemplateOutlet]="filterGroup.filterTemplate ?? defaultFilterLabelTemplate"
|
||||
></ng-container>
|
||||
</mat-checkbox>
|
||||
|
||||
<ng-container [ngTemplateOutletContext]="{ filter: child }" [ngTemplateOutlet]="actionsTemplate"></ng-container>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</ng-template>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<ng-container *ngIf="primaryFilterGroup$ | async as primaryGroup">
|
||||
<ng-container *ngIf="primaryGroup.icon">
|
||||
@if (primaryFilterGroup$ | async; as primaryGroup) {
|
||||
@if (primaryGroup.icon) {
|
||||
<iqser-icon-button
|
||||
[attr.aria-expanded]="expanded$ | async"
|
||||
[class.disabled]="primaryFiltersDisabled$ | async"
|
||||
@ -10,9 +10,8 @@
|
||||
[showDot]="hasActiveFilters$ | async"
|
||||
buttonId="{{ primaryGroup.slug }}"
|
||||
></iqser-icon-button>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!primaryGroup.icon">
|
||||
}
|
||||
@if (!primaryGroup.icon) {
|
||||
<iqser-chevron-button
|
||||
[attr.aria-expanded]="expanded$ | async"
|
||||
[class.disabled]="primaryFiltersDisabled$ | async"
|
||||
@ -21,8 +20,7 @@
|
||||
[matMenuTriggerFor]="filterMenu"
|
||||
[showDot]="hasActiveFilters$ | async"
|
||||
></iqser-chevron-button>
|
||||
</ng-container>
|
||||
|
||||
}
|
||||
<mat-menu
|
||||
#filterMenu="matMenu"
|
||||
(closed)="expanded.next(false)"
|
||||
@ -41,4 +39,4 @@
|
||||
</ng-template>
|
||||
</div>
|
||||
</mat-menu>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<ng-container *ngIf="quickFilters$ | async as filters">
|
||||
@if (quickFilters$ | async; as filters) {
|
||||
@for (filter of filters; track filter) {
|
||||
<div
|
||||
(click)="filterService.toggleFilter('quickFilters', filter.id)"
|
||||
*ngFor="let filter of filters"
|
||||
[class.active]="filter.checked"
|
||||
[class.disabled]="filter.disabled"
|
||||
class="quick-filter"
|
||||
@ -9,4 +9,5 @@
|
||||
>
|
||||
{{ filter.label }}
|
||||
</div>
|
||||
</ng-container>
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<iqser-icon-button
|
||||
*ngIf="type() === 'text' && icon()"
|
||||
@if (type() === 'text' && icon()) {
|
||||
<iqser-icon-button
|
||||
[attr.aria-expanded]="expanded()"
|
||||
[class.disabled]="disabled()"
|
||||
[disabled]="disabled()"
|
||||
@ -7,42 +7,45 @@
|
||||
[label]="label()"
|
||||
[matMenuTriggerFor]="filterMenu"
|
||||
[showDot]="hasActiveFilters()"
|
||||
></iqser-icon-button>
|
||||
></iqser-icon-button>
|
||||
}
|
||||
|
||||
<iqser-chevron-button
|
||||
@if (type() === 'text' && !icon()) {
|
||||
<iqser-chevron-button
|
||||
[attr.aria-expanded]="expanded()"
|
||||
[class.disabled]="disabled()"
|
||||
[disabled]="disabled()"
|
||||
[label]="label()"
|
||||
[matMenuTriggerFor]="filterMenu"
|
||||
[showDot]="hasActiveFilters()"
|
||||
*ngIf="type() === 'text' && !icon()"
|
||||
></iqser-chevron-button>
|
||||
></iqser-chevron-button>
|
||||
}
|
||||
|
||||
<iqser-circle-button
|
||||
@if (type() === 'icon') {
|
||||
<iqser-circle-button
|
||||
[attr.aria-expanded]="expanded()"
|
||||
[class.disabled]="disabled()"
|
||||
[disabled]="disabled()"
|
||||
[matMenuTriggerFor]="filterMenu"
|
||||
[showDot]="hasActiveFilters()"
|
||||
[icon]="icon() || 'iqser:filter-list'"
|
||||
*ngIf="type() === 'icon'"
|
||||
></iqser-circle-button>
|
||||
></iqser-circle-button>
|
||||
}
|
||||
|
||||
<mat-menu #filterMenu="matMenu" (closed)="expanded.set(false)" xPosition="before">
|
||||
<div iqserStopPropagation>
|
||||
<ng-template matMenuContent>
|
||||
<div class="input-wrapper">
|
||||
<iqser-input-with-action
|
||||
[value]="searchValue()"
|
||||
(valueChange)="searchValue.set($event)"
|
||||
[placeholder]="filterPlaceholder()"
|
||||
[value]="searchValue()"
|
||||
[width]="'full'"
|
||||
></iqser-input-with-action>
|
||||
</div>
|
||||
|
||||
<div class="filter-menu-header">
|
||||
<div translate="filter-menu.label" class="all-caps-label"></div>
|
||||
<div class="all-caps-label" translate="filter-menu.label"></div>
|
||||
<div class="actions">
|
||||
<div (click)="_selectAll()" class="all-caps-label primary pointer" iqserStopPropagation translate="actions.all"></div>
|
||||
<div (click)="_clear()" class="all-caps-label primary pointer" iqserStopPropagation translate="actions.none"></div>
|
||||
@ -50,11 +53,13 @@
|
||||
</div>
|
||||
|
||||
<div class="filter-content">
|
||||
<div mat-menu-item *ngFor="let option of displayedOptions()" (click)="_filterCheckboxClicked(option)">
|
||||
@for (option of displayedOptions(); track option) {
|
||||
<div mat-menu-item (click)="_filterCheckboxClicked(option)">
|
||||
<mat-checkbox [checked]="selectedOptions().includes(option)" class="filter-menu-checkbox">
|
||||
<span class="clamp-1">{{ option.label }}</span>
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Component, computed, effect, input, output, signal, untracked } from '@angular/core';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatCheckbox } from '@angular/material/checkbox';
|
||||
import { ChevronButtonComponent, CircleButtonComponent, IconButtonComponent } from '../../buttons';
|
||||
@ -14,7 +14,6 @@ import { SimpleFilterOption } from '../models/simple-filter-option';
|
||||
styleUrls: ['./simple-popup-filter.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatMenuModule,
|
||||
IconButtonComponent,
|
||||
ChevronButtonComponent,
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
<div *ngIf="helpModeService.isHelpModeActive$ | async">
|
||||
@if (helpModeService.isHelpModeActive$ | async) {
|
||||
<div>
|
||||
<div class="help-mode-border"></div>
|
||||
<div class="bottom small-label full-opacity">
|
||||
<strong>{{ 'help-mode.bottom-text' | translate }}</strong>
|
||||
<a (click)="helpModeService.openHelpModeDialog()" *ngIf="(helpModeService.helpModeDialogIsOpened$ | async) === false">
|
||||
@if ((helpModeService.helpModeDialogIsOpened$ | async) === false) {
|
||||
<a (click)="helpModeService.openHelpModeDialog()">
|
||||
{{ 'help-mode.instructions' | translate }}
|
||||
</a>
|
||||
}
|
||||
<div class="close">
|
||||
(esc)
|
||||
<iqser-circle-button
|
||||
@ -16,4 +19,5 @@
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<div [class.row]="displayInRow" class="iqser-input-group">
|
||||
@for (option of options; track option) {
|
||||
<div
|
||||
(click)="toggleOption(option)"
|
||||
*ngFor="let option of options"
|
||||
[class.active]="option.value === value?.value"
|
||||
[class.disabled]="option.disabled"
|
||||
[id]="groupId(option)"
|
||||
@ -10,14 +10,14 @@
|
||||
[ngClass]="{ 'mb-8': !displayInRow, 'mr-8': displayInRow }"
|
||||
class="option pointer"
|
||||
>
|
||||
<div *ngIf="option.icon; else withoutIcon" class="icon-option">
|
||||
@if (option.icon) {
|
||||
<div class="icon-option">
|
||||
<mat-icon [svgIcon]="option.icon" class="icon"></mat-icon>
|
||||
|
||||
<div class="text">
|
||||
<label class="details-radio-label pointer">{{ option.label | translate: option.descriptionParams }}</label>
|
||||
<span class="hint">{{ option.description | translate: option.descriptionParams | replaceNbsp }}</span>
|
||||
|
||||
<div *ngIf="option.extraOption && !option.extraOption.hidden && isSelected(option)" class="iqser-input-group">
|
||||
@if (option.extraOption && !option.extraOption.hidden && isSelected(option)) {
|
||||
<div class="iqser-input-group">
|
||||
<mat-checkbox
|
||||
(change)="emitExtraOption()"
|
||||
[(ngModel)]="option.extraOption.checked"
|
||||
@ -27,24 +27,26 @@
|
||||
>
|
||||
{{ option.extraOption.label | translate }}
|
||||
</mat-checkbox>
|
||||
@if (option.extraOption.description) {
|
||||
<span
|
||||
*ngIf="option.extraOption.description"
|
||||
[innerHTML]="option.extraOption.description | translate"
|
||||
class="hint extra-option-description"
|
||||
></span>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<mat-icon *ngIf="isSelected(option)" class="checked" svgIcon="iqser:radio-selected"></mat-icon>
|
||||
@if (isSelected(option)) {
|
||||
<mat-icon class="checked" svgIcon="iqser:radio-selected"></mat-icon>
|
||||
}
|
||||
</div>
|
||||
|
||||
<ng-template #withoutIcon>
|
||||
} @else {
|
||||
<div class="flex-align-items-center mb-8">
|
||||
<iqser-round-checkbox [active]="isSelected(option)" class="mr-6"></iqser-round-checkbox>
|
||||
<label class="details-radio-label pointer">{{ option.label | translate }}</label>
|
||||
</div>
|
||||
|
||||
<span class="hint">{{ option.description | translate }}</span>
|
||||
</ng-template>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { NgClass, NgForOf, NgIf } from '@angular/common';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { booleanAttribute, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { FormsModule, NG_VALIDATORS, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@ -28,12 +28,10 @@ import { DetailsRadioOption } from './details-radio-option';
|
||||
},
|
||||
],
|
||||
imports: [
|
||||
NgForOf,
|
||||
NgClass,
|
||||
RoundCheckboxComponent,
|
||||
TranslateModule,
|
||||
MatIconModule,
|
||||
NgIf,
|
||||
FormsModule,
|
||||
MatCheckboxModule,
|
||||
ReactiveFormsModule,
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
<div [class.datepicker-wrapper]="isDate" [ngClass]="classList" class="iqser-input-group">
|
||||
<label *ngIf="label"> {{ label }} </label>
|
||||
@if (label) {
|
||||
<label> {{ label }} </label>
|
||||
}
|
||||
|
||||
<ng-container *ngIf="isDate">
|
||||
@if (isDate) {
|
||||
<input
|
||||
(ngModelChange)="onChange($event)"
|
||||
[(ngModel)]="input"
|
||||
@ -15,11 +17,11 @@
|
||||
<mat-icon matDatepickerToggleIcon svgIcon="iqser:calendar"></mat-icon>
|
||||
</mat-datepicker-toggle>
|
||||
<mat-datepicker #picker (closed)="onCloseDatepicker()" (opened)="onOpenDatepicker()"></mat-datepicker>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
@if (isText) {
|
||||
<input
|
||||
(ngModelChange)="onChange($event)"
|
||||
*ngIf="isText"
|
||||
[(ngModel)]="input"
|
||||
[disabled]="disabled"
|
||||
[id]="id"
|
||||
@ -27,14 +29,9 @@
|
||||
iqserStopPropagation
|
||||
type="text"
|
||||
/>
|
||||
}
|
||||
|
||||
<input
|
||||
(ngModelChange)="onChange($event)"
|
||||
*ngIf="isNumber"
|
||||
[(ngModel)]="input"
|
||||
[disabled]="disabled"
|
||||
[id]="id"
|
||||
iqserStopPropagation
|
||||
type="number"
|
||||
/>
|
||||
@if (isNumber) {
|
||||
<input (ngModelChange)="onChange($event)" [(ngModel)]="input" [disabled]="disabled" [id]="id" iqserStopPropagation type="number" />
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { FormsModule, NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { FormFieldComponent } from '../form-field/form-field-component.directive';
|
||||
import { NgClass, NgIf } from '@angular/common';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { StopPropagationDirective } from '../../directives';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
@ -36,7 +36,7 @@ type DynamicInput = number | string | Date;
|
||||
useExisting: DynamicInputComponent,
|
||||
},
|
||||
],
|
||||
imports: [NgClass, NgIf, FormsModule, MatDatepickerModule, StopPropagationDirective, MatIconModule, MatInputModule],
|
||||
imports: [NgClass, FormsModule, MatDatepickerModule, StopPropagationDirective, MatIconModule, MatInputModule],
|
||||
})
|
||||
export class DynamicInputComponent extends FormFieldComponent<DynamicInput> {
|
||||
@Input() label?: string;
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
<ng-container *ngIf="!editing">
|
||||
<div *ngIf="showPreview">
|
||||
@if (!editing) {
|
||||
@if (showPreview) {
|
||||
<div>
|
||||
{{ value }}
|
||||
</div>
|
||||
|
||||
}
|
||||
<div class="flex">
|
||||
@if (canEdit) {
|
||||
<iqser-circle-button
|
||||
*ngIf="canEdit"
|
||||
(action)="editing = true"
|
||||
[tooltip]="editTooltip"
|
||||
[type]="buttonsType"
|
||||
@ -13,22 +14,17 @@
|
||||
class="edit-button"
|
||||
icon="iqser:edit"
|
||||
></iqser-circle-button>
|
||||
|
||||
}
|
||||
<ng-content select="[slot=editing]"></ng-content>
|
||||
</div>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
<ng-container *ngIf="editing">
|
||||
@if (editing) {
|
||||
<form (submit)="saveValue()">
|
||||
<div [class]="'iqser-input-group ' + class">
|
||||
<input
|
||||
*ngIf="!parentId; else expandableInput"
|
||||
(ngModelChange)="newValue = $event"
|
||||
[ngModel]="value"
|
||||
[placeholder]="placeholder"
|
||||
name="name"
|
||||
/>
|
||||
<ng-template #expandableInput>
|
||||
@if (!parentId) {
|
||||
<input (ngModelChange)="newValue = $event" [ngModel]="value" [placeholder]="placeholder" name="name" />
|
||||
} @else {
|
||||
<textarea
|
||||
(ngModelChange)="newValue = $event"
|
||||
[ngModel]="value"
|
||||
@ -38,13 +34,11 @@
|
||||
[style.width]="this.textArea.width + 'px'"
|
||||
[style.height]="this.textArea.height + 'px'"
|
||||
></textarea>
|
||||
</ng-template>
|
||||
}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="flex">
|
||||
<iqser-circle-button (action)="saveValue()" [tooltip]="saveTooltip" [type]="buttonsType" icon="iqser:check"></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="editing = false"
|
||||
[tooltip]="cancelTooltip"
|
||||
@ -52,4 +46,4 @@
|
||||
icon="iqser:close"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { NgIf } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, HostBinding, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CircleButtonComponent, CircleButtonType, CircleButtonTypes } from '../../buttons';
|
||||
@ -9,7 +8,7 @@ import { CircleButtonComponent, CircleButtonType, CircleButtonTypes } from '../.
|
||||
styleUrls: ['./editable-input.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [NgIf, CircleButtonComponent, FormsModule],
|
||||
imports: [CircleButtonComponent, FormsModule],
|
||||
})
|
||||
export class EditableInputComponent implements OnChanges {
|
||||
@Input() id?: string;
|
||||
|
||||
@ -11,22 +11,24 @@
|
||||
type="text"
|
||||
/>
|
||||
|
||||
<span *ngIf="hint" class="hint">{{ hint }}</span>
|
||||
@if (hint) {
|
||||
<span class="hint">{{ hint }}</span>
|
||||
}
|
||||
|
||||
<mat-icon *ngIf="isSearch && !hasContent" class="icon-right" svgIcon="iqser:search"></mat-icon>
|
||||
@if (isSearch && !hasContent) {
|
||||
<mat-icon class="icon-right" svgIcon="iqser:search"></mat-icon>
|
||||
}
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="reset()"
|
||||
*ngIf="isSearch && hasContent"
|
||||
[buttonId]="inputId + '-clear'"
|
||||
icon="iqser:close"
|
||||
></iqser-circle-button>
|
||||
@if (isSearch && hasContent) {
|
||||
<iqser-circle-button (action)="reset()" [buttonId]="inputId + '-clear'" icon="iqser:close"></iqser-circle-button>
|
||||
}
|
||||
|
||||
@if (!isSearch) {
|
||||
<iqser-circle-button
|
||||
(action)="executeAction()"
|
||||
*ngIf="!isSearch"
|
||||
[buttonId]="actionButtonId"
|
||||
[disabled]="!hasContent"
|
||||
[icon]="icon!"
|
||||
></iqser-circle-button>
|
||||
}
|
||||
</form>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { randomString } from '../../utils';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { NgIf } from '@angular/common';
|
||||
|
||||
import { CircleButtonComponent } from '../../buttons';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
@ -11,7 +11,7 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
styleUrls: ['./input-with-action.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [FormsModule, NgIf, MatIconModule, CircleButtonComponent],
|
||||
imports: [FormsModule, MatIconModule, CircleButtonComponent],
|
||||
})
|
||||
export class InputWithActionComponent {
|
||||
@Input() inputId = `${randomString() + '-search-input'}`;
|
||||
|
||||
@ -6,6 +6,10 @@
|
||||
[class.with-bg]="type === 'with-bg'"
|
||||
class="wrapper"
|
||||
>
|
||||
<mat-icon *ngIf="active && !indeterminate" svgIcon="iqser:radio-selected"></mat-icon>
|
||||
<mat-icon *ngIf="indeterminate" svgIcon="iqser:radio-indeterminate"></mat-icon>
|
||||
@if (active && !indeterminate) {
|
||||
<mat-icon svgIcon="iqser:radio-selected"></mat-icon>
|
||||
}
|
||||
@if (indeterminate) {
|
||||
<mat-icon svgIcon="iqser:radio-indeterminate"></mat-icon>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { booleanAttribute, ChangeDetectionStrategy, Component, ElementRef, HostBinding, Input, OnInit, ViewChild } from '@angular/core';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { NgIf } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-round-checkbox',
|
||||
@ -8,7 +7,7 @@ import { NgIf } from '@angular/common';
|
||||
styleUrls: ['./round-checkbox.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [MatIconModule, NgIf],
|
||||
imports: [MatIconModule],
|
||||
})
|
||||
export class RoundCheckboxComponent implements OnInit {
|
||||
@Input() size = 20;
|
||||
|
||||
@ -1,94 +1,98 @@
|
||||
<div class="page-header">
|
||||
<div *ngIf="pageLabel" class="breadcrumb">{{ pageLabel }}</div>
|
||||
@if (pageLabel) {
|
||||
<div class="breadcrumb">{{ pageLabel }}</div>
|
||||
}
|
||||
|
||||
<div *ngIf="filters$ | async as filters" class="filters">
|
||||
@if (filters$ | async; as filters) {
|
||||
<div class="filters">
|
||||
<ng-content select="[slot=beforeFilters]"></ng-content>
|
||||
|
||||
<div
|
||||
*ngIf="filters.length && searchPosition !== searchPositions.beforeFilters"
|
||||
class="text-muted"
|
||||
translate="filters.filter-by"
|
||||
></div>
|
||||
|
||||
<ng-container *ngIf="searchPosition === searchPositions.beforeFilters" [ngTemplateOutlet]="searchBar"></ng-container>
|
||||
|
||||
<ng-container *ngFor="let filter of filters; trackBy: trackByLabel">
|
||||
<iqser-popup-filter
|
||||
*ngIf="!filter.hide"
|
||||
[primaryFiltersSlug]="filter.slug"
|
||||
[attr.help-mode-key]="filterHelpModeKey"
|
||||
></iqser-popup-filter>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let filter$ of filterService.singleFilters">
|
||||
<iqser-single-filter *ngIf="filter$ | async as filter" [filter]="filter"></iqser-single-filter>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="searchPosition === searchPositions.afterFilters" [ngTemplateOutlet]="searchBar"></ng-container>
|
||||
|
||||
@if (filters.length && searchPosition !== searchPositions.beforeFilters) {
|
||||
<div class="text-muted" translate="filters.filter-by"></div>
|
||||
}
|
||||
@if (searchPosition === searchPositions.beforeFilters) {
|
||||
<ng-container [ngTemplateOutlet]="searchBar"></ng-container>
|
||||
}
|
||||
@for (filter of filters; track trackByLabel($index, filter)) {
|
||||
@if (!filter.hide) {
|
||||
<iqser-popup-filter [primaryFiltersSlug]="filter.slug" [attr.help-mode-key]="filterHelpModeKey"></iqser-popup-filter>
|
||||
}
|
||||
}
|
||||
@for (filter$ of filterService.singleFilters; track filter$) {
|
||||
@if (filter$ | async; as filter) {
|
||||
<iqser-single-filter [filter]="filter"></iqser-single-filter>
|
||||
}
|
||||
}
|
||||
@if (searchPosition === searchPositions.afterFilters) {
|
||||
<ng-container [ngTemplateOutlet]="searchBar"></ng-container>
|
||||
}
|
||||
@if (!hideResetButton && (showResetFilters$ | async) === true) {
|
||||
<div
|
||||
(click)="resetFilters()"
|
||||
*ngIf="!hideResetButton && (showResetFilters$ | async) === true"
|
||||
[attr.help-mode-key]="'filter_' + helpModeKey + '_list'"
|
||||
class="reset-filters"
|
||||
translate="reset-filters"
|
||||
></div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div *ngIf="showCloseButton || actionConfigs || buttonConfigs || viewModeSelection" class="actions">
|
||||
<ng-container *ngIf="searchPosition === searchPositions.withActions" [ngTemplateOutlet]="searchBar"></ng-container>
|
||||
|
||||
@if (showCloseButton || actionConfigs || buttonConfigs || viewModeSelection) {
|
||||
<div class="actions">
|
||||
@if (searchPosition === searchPositions.withActions) {
|
||||
<ng-container [ngTemplateOutlet]="searchBar"></ng-container>
|
||||
}
|
||||
<ng-container [ngTemplateOutlet]="viewModeSelection"></ng-container>
|
||||
|
||||
<ng-container *ngFor="let config of buttonConfigs; trackBy: trackByLabel">
|
||||
@for (config of buttonConfigs; track trackByLabel($index, config)) {
|
||||
@if (!config.hide) {
|
||||
<iqser-icon-button
|
||||
(action)="config.action($event)"
|
||||
*ngIf="!config.hide"
|
||||
[buttonId]="config.label.replace('.', '-')"
|
||||
[icon]="config.icon"
|
||||
[label]="config.label | translate"
|
||||
[type]="config.type"
|
||||
[attr.help-mode-key]="config.helpModeKey"
|
||||
></iqser-icon-button>
|
||||
</ng-container>
|
||||
|
||||
}
|
||||
}
|
||||
<div class="actions">
|
||||
<ng-container *ngFor="let config of actionConfigs; trackBy: trackByLabel">
|
||||
@for (config of actionConfigs; track trackByLabel($index, config)) {
|
||||
@if (!config.hide) {
|
||||
<iqser-circle-button
|
||||
(action)="config.action($event)"
|
||||
*ngIf="!config.hide"
|
||||
[buttonId]="config.id"
|
||||
[disabled]="config.disabled$ && (config.disabled$ | async)"
|
||||
[icon]="config.icon"
|
||||
[tooltip]="config.label"
|
||||
[attr.help-mode-key]="config.helpModeKey"
|
||||
></iqser-circle-button>
|
||||
</ng-container>
|
||||
|
||||
}
|
||||
}
|
||||
<!-- Extra custom actions here -->
|
||||
<ng-content select="[slot=right]"></ng-content>
|
||||
|
||||
@if (showCloseButton) {
|
||||
<iqser-circle-button
|
||||
buttonId="close-view-btn"
|
||||
(action)="closeAction.emit()"
|
||||
*ngIf="showCloseButton"
|
||||
[class.ml-6]="actionConfigs"
|
||||
[icon]="'iqser:close'"
|
||||
[attr.help-mode-key]="'close_dossier'"
|
||||
[tooltip]="'common.close' | translate"
|
||||
></iqser-circle-button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<ng-template #searchBar>
|
||||
@if (searchPlaceholder && searchService) {
|
||||
<iqser-input-with-action
|
||||
[inputId]="searchInputId"
|
||||
(valueChange)="searchService.searchValue = $event"
|
||||
*ngIf="searchPlaceholder && searchService"
|
||||
[class.mr-8]="searchPosition === searchPositions.beforeFilters"
|
||||
[placeholder]="searchPlaceholder"
|
||||
[value]="searchService.valueChanges$ | async"
|
||||
[width]="searchWidth"
|
||||
></iqser-input-with-action>
|
||||
}
|
||||
</ng-template>
|
||||
|
||||
@ -1,14 +1,24 @@
|
||||
<div (click)="!!sortByKey && sortingService?.toggleSort(sortByKey)" [class.pointer]="!!sortByKey" [ngClass]="class">
|
||||
<mat-icon *ngIf="!!leftIcon" [svgIcon]="leftIcon"></mat-icon>
|
||||
@if (!!leftIcon) {
|
||||
<mat-icon [svgIcon]="leftIcon"></mat-icon>
|
||||
}
|
||||
|
||||
<span [matTooltip]="label" class="all-caps-label clamp-1" matTooltipPosition="above">{{ label }}</span>
|
||||
|
||||
<mat-icon *ngIf="!!rightIcon" [matTooltip]="rightIconTooltip | translate" [svgIcon]="rightIcon" matTooltipPosition="above"></mat-icon>
|
||||
@if (!!rightIcon) {
|
||||
<mat-icon [matTooltip]="rightIconTooltip | translate" [svgIcon]="rightIcon" matTooltipPosition="above"></mat-icon>
|
||||
}
|
||||
|
||||
<ng-container *ngIf="sortingService?.sortingOption$ | async as sortingOption">
|
||||
<div *ngIf="!!sortByKey" [class.force-display]="sortingOption.column === sortByKey" class="sort-arrows-container">
|
||||
<mat-icon *ngIf="sortingOption.order === sortingOrders.asc" svgIcon="iqser:sort-asc"></mat-icon>
|
||||
<mat-icon *ngIf="sortingOption.order === sortingOrders.desc" svgIcon="iqser:sort-desc"></mat-icon>
|
||||
@if (sortingService?.sortingOption$ | async; as sortingOption) {
|
||||
@if (!!sortByKey) {
|
||||
<div [class.force-display]="sortingOption.column === sortByKey" class="sort-arrows-container">
|
||||
@if (sortingOption.order === sortingOrders.asc) {
|
||||
<mat-icon svgIcon="iqser:sort-asc"></mat-icon>
|
||||
}
|
||||
@if (sortingOption.order === sortingOrders.desc) {
|
||||
<mat-icon svgIcon="iqser:sort-desc"></mat-icon>
|
||||
}
|
||||
</div>
|
||||
</ng-container>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -10,10 +10,10 @@
|
||||
<ng-container *cdkVirtualFor="let entity of listingService.sortedDisplayedEntities$ | async; trackBy: trackBy">
|
||||
<!-- mouseenter and mouseleave triggers change detection event if itemMouse functions are undefined -->
|
||||
<!-- this little hack below ensures that change detection won't be triggered if functions are undefined -->
|
||||
@if (itemMouseEnterFn || itemMouseLeaveFn) {
|
||||
<div
|
||||
(mouseenter)="itemMouseEnterFn && itemMouseEnterFn(entity)"
|
||||
(mouseleave)="itemMouseLeaveFn && itemMouseLeaveFn(entity)"
|
||||
*ngIf="itemMouseEnterFn || itemMouseLeaveFn; else withoutMouseEvents"
|
||||
[class.help-mode-active]="helpModeService?.isHelpModeActive$ | async"
|
||||
[id]="rowIdPrefix + '-' + ((entity[namePropertyKey] | snakeCase) ?? entity.id)"
|
||||
[ngClass]="getTableItemClasses(entity)"
|
||||
@ -25,8 +25,7 @@
|
||||
[selectionEnabled]="selectionEnabled"
|
||||
></iqser-table-item>
|
||||
</div>
|
||||
|
||||
<ng-template #withoutMouseEvents>
|
||||
} @else {
|
||||
<div
|
||||
[class.help-mode-active]="helpModeService?.isHelpModeActive$ | async"
|
||||
[id]="rowIdPrefix + '-' + ((entity[namePropertyKey] | snakeCase) ?? entity.id)"
|
||||
@ -39,7 +38,7 @@
|
||||
[selectionEnabled]="selectionEnabled"
|
||||
></iqser-table-item>
|
||||
</div>
|
||||
</ng-template>
|
||||
}
|
||||
</ng-container>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
<div [id]="'select-' + entity.id" (click)="toggleEntitySelected($event, entity)" *ngIf="selectionEnabled" class="selection-column">
|
||||
@if (selectionEnabled) {
|
||||
<div [id]="'select-' + entity.id" (click)="toggleEntitySelected($event, entity)" class="selection-column">
|
||||
<iqser-round-checkbox [active]="isSelected$ | async"></iqser-round-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<ng-container *ngTemplateOutlet="listingComponent.tableItemTemplate; context: { entity: entity }"></ng-container>
|
||||
|
||||
|
||||
@ -1,40 +1,44 @@
|
||||
<div [class.selection-enabled]="selectionEnabled" class="header-item">
|
||||
<div [attr.help-mode-key]="helpModeKey" class="header-title">
|
||||
@if (selectionEnabled) {
|
||||
<iqser-round-checkbox
|
||||
(click)="listingService.selectAll()"
|
||||
*ngIf="selectionEnabled"
|
||||
[active]="listingService.areAllSelected$ | async"
|
||||
[indeterminate]="listingService.notAllSelected$ | async"
|
||||
id="select-all-entities-toggle"
|
||||
></iqser-round-checkbox>
|
||||
}
|
||||
|
||||
<span class="all-caps-label">
|
||||
{{ tableHeaderLabel | translate: { length: totalSize || (listingService.displayedLength$ | async) } }}
|
||||
<span *ngIf="listingService.selectedLength$ | async as selectedItems">
|
||||
({{ 'table-header.selected-count' | translate: { count: selectedItems } }})
|
||||
</span>
|
||||
@if (listingService.selectedLength$ | async; as selectedItems) {
|
||||
<span> ({{ 'table-header.selected-count' | translate: { count: selectedItems } }}) </span>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ng-container [ngTemplateOutlet]="bulkActions"></ng-container>
|
||||
|
||||
<iqser-quick-filters *ngIf="quickFilters$ | async"></iqser-quick-filters>
|
||||
@if (quickFilters$ | async) {
|
||||
<iqser-quick-filters></iqser-quick-filters>
|
||||
}
|
||||
|
||||
<!-- Custom content-->
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
|
||||
<div
|
||||
*ngIf="listingMode === listingModes.table"
|
||||
@if (listingMode === listingModes.table) {
|
||||
<div
|
||||
[class.no-data]="entitiesService.noData$ | async"
|
||||
[class.selection-enabled]="selectionEnabled"
|
||||
class="table-header"
|
||||
iqserSyncWidth="table-item"
|
||||
>
|
||||
<div *ngIf="selectionEnabled" class="select-oval-placeholder"></div>
|
||||
|
||||
>
|
||||
@if (selectionEnabled) {
|
||||
<div class="select-oval-placeholder"></div>
|
||||
}
|
||||
@for (config of tableColumnConfigs; track config) {
|
||||
<iqser-table-column-name
|
||||
*ngFor="let config of tableColumnConfigs"
|
||||
[class]="config.class"
|
||||
[id]="config.id"
|
||||
[label]="config.notTranslatable ? config.label : (config.label | translate)"
|
||||
@ -43,8 +47,10 @@
|
||||
[rightIcon]="config.rightIcon"
|
||||
[sortByKey]="config.sortByKey"
|
||||
></iqser-table-column-name>
|
||||
|
||||
<div *ngIf="hasEmptyColumn"></div>
|
||||
|
||||
}
|
||||
@if (hasEmptyColumn) {
|
||||
<div></div>
|
||||
}
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -1,42 +1,46 @@
|
||||
<iqser-table-header
|
||||
[bulkActions]="bulkActions"
|
||||
[hasEmptyColumn]="!!emptyColumnWidth"
|
||||
[helpModeKey]="headerHelpModeKey"
|
||||
[listingMode]="listingModes.table"
|
||||
[selectionEnabled]="selectionEnabled"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[tableHeaderLabel]="tableHeaderLabel"
|
||||
[helpModeKey]="headerHelpModeKey"
|
||||
[totalSize]="totalSize"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
|
||||
</iqser-table-header>
|
||||
|
||||
<iqser-empty-state
|
||||
@if (entitiesService.noData$ | async) {
|
||||
<iqser-empty-state
|
||||
(action)="noDataAction.emit()"
|
||||
*ngIf="entitiesService.noData$ | async"
|
||||
[buttonIcon]="noDataButtonIcon"
|
||||
[buttonLabel]="noDataButtonLabel"
|
||||
[icon]="noDataIcon"
|
||||
[showButton]="showNoDataButton"
|
||||
[text]="noDataText"
|
||||
></iqser-empty-state>
|
||||
></iqser-empty-state>
|
||||
}
|
||||
|
||||
<iqser-empty-state *ngIf="listingComponent.noMatch$ | async" [text]="noMatchText"></iqser-empty-state>
|
||||
@if (listingComponent.noMatch$ | async) {
|
||||
<iqser-empty-state [text]="noMatchText"></iqser-empty-state>
|
||||
}
|
||||
|
||||
<iqser-table-content
|
||||
#tableContent
|
||||
[itemMouseEnterFn]="itemMouseEnterFn"
|
||||
[itemMouseLeaveFn]="itemMouseLeaveFn"
|
||||
[itemSize]="itemSize"
|
||||
[namePropertyKey]="namePropertyKey"
|
||||
[rowIdPrefix]="rowIdPrefix"
|
||||
[selectionEnabled]="selectionEnabled"
|
||||
[tableItemClasses]="tableItemClasses"
|
||||
[rowIdPrefix]="rowIdPrefix"
|
||||
[namePropertyKey]="namePropertyKey"
|
||||
></iqser-table-content>
|
||||
|
||||
<iqser-scroll-button
|
||||
*ngIf="hasScrollButton && tableContent?.scrollViewport"
|
||||
@if (hasScrollButton && tableContent?.scrollViewport) {
|
||||
<iqser-scroll-button
|
||||
[itemSize]="itemSize"
|
||||
[scrollViewport]="tableContent.scrollViewport"
|
||||
[helpModeKey]="helpModeKey"
|
||||
></iqser-scroll-button>
|
||||
></iqser-scroll-button>
|
||||
}
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
<ng-container *ngIf="componentContext$ | async as ctx">
|
||||
<ng-container *ngIf="ctx.entities as entities">
|
||||
@if (componentContext$ | async; as ctx) {
|
||||
@if (ctx.entities; as entities) {
|
||||
<div class="heading">
|
||||
<span>{{ column.label | translate }} ({{ entities.length || 0 }})</span>
|
||||
<span
|
||||
(click)="enableSelection()"
|
||||
*ngIf="!activeSelection && !selectionColumn && entities.length > 1"
|
||||
class="all-caps-label primary pointer"
|
||||
translate="workflow.selection.select"
|
||||
></span>
|
||||
<div *ngIf="activeSelection" class="flex">
|
||||
@if (!activeSelection && !selectionColumn && entities.length > 1) {
|
||||
<span (click)="enableSelection()" class="all-caps-label primary pointer" translate="workflow.selection.select"></span>
|
||||
}
|
||||
@if (activeSelection) {
|
||||
<div class="flex">
|
||||
<span (click)="selectAll()" class="all-caps-label primary pointer mr-10" translate="workflow.selection.all"></span>
|
||||
<span (click)="selectNone()" class="all-caps-label primary pointer" translate="workflow.selection.none"></span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div *ngIf="activeSelection" class="multi-select mb-8">
|
||||
@if (activeSelection) {
|
||||
<div class="multi-select mb-8">
|
||||
<div class="selected-wrapper">
|
||||
<iqser-round-checkbox
|
||||
(click)="toggleSelectAll()"
|
||||
@ -21,23 +21,26 @@
|
||||
[indeterminate]="ctx.indeterminate"
|
||||
type="with-bg"
|
||||
></iqser-round-checkbox>
|
||||
|
||||
<span
|
||||
[translateParams]="{ count: listingService.selectedLength$ | async }"
|
||||
[translate]="'workflow.selection.count'"
|
||||
class="all-caps-label"
|
||||
></span>
|
||||
</div>
|
||||
|
||||
<div #bulkActionsContainer class="flex-1 overflow-hidden">
|
||||
@if (bulkActionsContainerWidth) {
|
||||
<ng-container
|
||||
*ngIf="bulkActionsContainerWidth"
|
||||
[ngTemplateOutletContext]="{ maxWidth: bulkActionsContainerWidth }"
|
||||
[ngTemplateOutlet]="bulkActions"
|
||||
></ng-container>
|
||||
}
|
||||
</div>
|
||||
|
||||
<iqser-circle-button (action)="disableSelection()" [type]="circleButtonTypes.primary" icon="iqser:close"></iqser-circle-button>
|
||||
<iqser-circle-button
|
||||
(action)="disableSelection()"
|
||||
[type]="circleButtonTypes.primary"
|
||||
icon="iqser:close"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
<ng-container *ngIf="componentContext$ | async as ctx">
|
||||
@if (componentContext$ | async; as ctx) {
|
||||
<iqser-table-header [tableHeaderLabel]="listingComponent.tableHeaderLabel" listingMode="workflow"></iqser-table-header>
|
||||
|
||||
@if (ctx.noData) {
|
||||
<iqser-empty-state
|
||||
(action)="noDataAction.emit()"
|
||||
*ngIf="ctx.noData"
|
||||
[buttonIcon]="noDataButtonIcon"
|
||||
[buttonLabel]="noDataButtonLabel"
|
||||
[icon]="noDataIcon"
|
||||
[showButton]="showNoDataButton"
|
||||
[text]="noDataText"
|
||||
></iqser-empty-state>
|
||||
|
||||
<div *ngIf="!ctx.noData" cdkDropListGroup class="columns-wrapper">
|
||||
}
|
||||
@if (!ctx.noData) {
|
||||
<div cdkDropListGroup class="columns-wrapper">
|
||||
@for (column of config.columns; track column) {
|
||||
<div
|
||||
*ngFor="let column of config.columns"
|
||||
[class.dragging]="dragging"
|
||||
[class.list-can-receive]="isReceiving(column)"
|
||||
[class.list-dragging]="isDragging(column)"
|
||||
@ -21,10 +21,14 @@
|
||||
[style.--color]="column.color"
|
||||
class="column"
|
||||
>
|
||||
<iqser-column-header [(selectionColumn)]="selectionColumn" [bulkActions]="bulkActions" [column]="column"></iqser-column-header>
|
||||
<iqser-column-header
|
||||
[(selectionColumn)]="selectionColumn"
|
||||
[bulkActions]="bulkActions"
|
||||
[column]="column"
|
||||
></iqser-column-header>
|
||||
@if (column.entities | async; as entities) {
|
||||
<div
|
||||
(cdkDropListDropped)="move($event)"
|
||||
*ngIf="column.entities | async as entities"
|
||||
[cdkDropListData]="entities"
|
||||
[cdkDropListEnterPredicate]="canMoveTo(column)"
|
||||
[class.multi-select-active]="selectionColumn === column"
|
||||
@ -32,38 +36,43 @@
|
||||
cdkDropList
|
||||
cdkDropListSortingDisabled
|
||||
>
|
||||
@for (entity of entities; track trackBy($index, entity)) {
|
||||
<div
|
||||
(cdkDragEnded)="stopDragging()"
|
||||
(cdkDragStarted)="startDragging(column, $event)"
|
||||
(click)="selectionColumn === column && listingService.select(entity)"
|
||||
*ngFor="let entity of entities; trackBy: trackBy"
|
||||
[cdkDragData]="entity"
|
||||
[class.no-border]="dragging && ctx.draggingEntities.includes(entity)"
|
||||
[class.selected]="all[entity.id].isSelected$ | async"
|
||||
[ngClass]="all[entity.id].classes$ | async"
|
||||
cdkDrag
|
||||
>
|
||||
<ng-container *ngIf="!ctx.draggingEntities.includes(entity)">
|
||||
@if (!ctx.draggingEntities.includes(entity)) {
|
||||
<ng-container *ngTemplateOutlet="itemTemplate; context: { entity: entity }"></ng-container>
|
||||
</ng-container>
|
||||
|
||||
}
|
||||
<ng-template cdkDragPlaceholder>
|
||||
<div *ngFor="let e of ctx.draggingEntities" [style.min-height]="itemHeight + 'px'" class="placeholder"></div>
|
||||
@for (e of ctx.draggingEntities; track e) {
|
||||
<div [style.min-height]="itemHeight + 'px'" class="placeholder"></div>
|
||||
}
|
||||
</ng-template>
|
||||
|
||||
<ng-template cdkDragPreview [matchSize]="true">
|
||||
<ng-container *ngFor="let e of ctx.draggingEntities">
|
||||
@for (e of ctx.draggingEntities; track e) {
|
||||
<div [class.selected]="all[e.id].isSelected$ | async" [ngClass]="all[e.id].classes$ | async">
|
||||
<ng-container *ngTemplateOutlet="itemTemplate; context: { entity: e }"></ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
}
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<div (click)="addElement.emit()" *ngIf="column.key === addElementColumn" class="add-btn">
|
||||
}
|
||||
@if (column.key === addElementColumn) {
|
||||
<div (click)="addElement.emit()" class="add-btn">
|
||||
<mat-icon [svgIcon]="addElementIcon"></mat-icon>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</ng-container>
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
<ng-container *ngIf="loadingService.isLoading() as config">
|
||||
@if (loadingService.isLoading(); as config) {
|
||||
<section class="full-page-section"></section>
|
||||
<section class="full-page-content">
|
||||
<mat-spinner *ngIf="config.type === 'spinner'" diameter="40"></mat-spinner>
|
||||
|
||||
<ng-container *ngIf="config.type === 'progress-bar'">
|
||||
@if (config.type === 'spinner') {
|
||||
<mat-spinner diameter="40"></mat-spinner>
|
||||
}
|
||||
@if (config.type === 'progress-bar') {
|
||||
<iqser-progress-loading [config]="config"></iqser-progress-loading>
|
||||
</ng-container>
|
||||
|
||||
}
|
||||
<ng-content></ng-content>
|
||||
</section>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, Optional } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Input, Optional, OnInit } from '@angular/core';
|
||||
import { ProgressBarConfigModel } from './progress-bar-config.model';
|
||||
import { FilterService, INestedFilter } from '../../filtering';
|
||||
import { Observable, of } from 'rxjs';
|
||||
@ -11,7 +11,7 @@ import { map } from 'rxjs/operators';
|
||||
styleUrls: ['./progress-bar.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ProgressBarComponent {
|
||||
export class ProgressBarComponent implements OnInit {
|
||||
@Input() config!: ProgressBarConfigModel;
|
||||
@Input() filterKey?: string;
|
||||
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
<h1 *ngIf="config.title">{{ config.title }}</h1>
|
||||
@if (config.title) {
|
||||
<h1>{{ config.title }}</h1>
|
||||
}
|
||||
|
||||
<div class="pt-8">
|
||||
<mat-progress-bar
|
||||
@ -8,10 +10,16 @@
|
||||
></mat-progress-bar>
|
||||
|
||||
<div class="pt-10">
|
||||
<ng-container *ngIf="config.value">{{ config.value }}%</ng-container>
|
||||
@if (config.value) {
|
||||
{{ config.value }}%
|
||||
}
|
||||
|
||||
<ng-container *ngIf="config.value && config.remainingTime"><span> - </span></ng-container>
|
||||
@if (config.value && config.remainingTime) {
|
||||
<span> - </span>
|
||||
}
|
||||
|
||||
<ng-container *ngIf="config.remainingTime">{{ config.remainingTime }} remaining...</ng-container>
|
||||
@if (config.remainingTime) {
|
||||
{{ config.remainingTime }} remaining...
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,26 +1,27 @@
|
||||
<div
|
||||
id="pagination-prev-page-btn"
|
||||
(click)="selectPage(currentPage - 1)"
|
||||
[class.disabled]="currentPage < 1"
|
||||
class="page"
|
||||
id="pagination-prev-page-btn"
|
||||
translate="pagination.previous"
|
||||
></div>
|
||||
<span>|</span>
|
||||
<div
|
||||
@for (page of displayedPages; track page) {
|
||||
<div
|
||||
(click)="selectPage(page)"
|
||||
*ngFor="let page of displayedPages"
|
||||
[class.active]="page === currentPage"
|
||||
[class.dots]="page === '...'"
|
||||
class="page"
|
||||
[id]="isNumber(page) ? 'pagination-select-page-' + page + '-btn' : 'pagination-pages-between'"
|
||||
>
|
||||
>
|
||||
{{ displayValue(page) }}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<span>|</span>
|
||||
<div
|
||||
id="pagination-next-page-btn"
|
||||
(click)="selectPage(currentPage + 1)"
|
||||
[class.disabled]="currentPage >= totalPages - 1"
|
||||
class="page"
|
||||
id="pagination-next-page-btn"
|
||||
translate="pagination.next"
|
||||
></div>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { NgForOf } from '@angular/common';
|
||||
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { PaginationSettings } from './pagination-settings';
|
||||
|
||||
@ -9,7 +9,7 @@ import { PaginationSettings } from './pagination-settings';
|
||||
styleUrls: ['./pagination.component.scss'],
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [NgForOf, TranslateModule],
|
||||
imports: [TranslateModule],
|
||||
})
|
||||
export class PaginationComponent {
|
||||
displayedPages: (number | string)[] = [];
|
||||
|
||||
@ -1,24 +1,23 @@
|
||||
```typescript
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { IqserPermissionsService } from "./permissions.service";
|
||||
import { IqserRolesService } from "./roles.service";
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { IqserPermissionsService } from './permissions.service';
|
||||
import { IqserRolesService } from './roles.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: "./app.component.html"
|
||||
templateUrl: './app.component.html',
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
constructor(
|
||||
private permissionsService: IqserPermissionsService,
|
||||
private rolesService: IqserRolesService
|
||||
) {
|
||||
}
|
||||
private rolesService: IqserRolesService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
const perm = ["can-edit-articles", "can-read-articles"];
|
||||
const perm = ['can-edit-articles', 'can-read-articles'];
|
||||
this.permissionsService.load(perm);
|
||||
|
||||
const roles = ["ADMIN", "EDITOR"];
|
||||
const roles = ['ADMIN', 'EDITOR'];
|
||||
this.rolesService.load(roles);
|
||||
}
|
||||
}
|
||||
@ -82,21 +81,21 @@ export class AppComponent implements OnInit {
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { IqserRoute } from "./models/permissions-router-data.model";
|
||||
import { IqserPermissionsGuard } from "./permissions-guard.service";
|
||||
import { IqserRoute } from './models/permissions-router-data.model';
|
||||
import { IqserPermissionsGuard } from './permissions-guard.service';
|
||||
|
||||
const appRoutes: IqserRoute[] = [
|
||||
{
|
||||
path: "home",
|
||||
path: 'home',
|
||||
component: HomeComponent,
|
||||
canActivate: [IqserPermissionsGuard],
|
||||
data: {
|
||||
permissions: {
|
||||
allow: ["ADMIN", "MODERATOR"],
|
||||
redirectTo: "/another-route"
|
||||
}
|
||||
}
|
||||
}
|
||||
allow: ['ADMIN', 'MODERATOR'],
|
||||
redirectTo: '/another-route',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const appRoutes1: IqserRoute[] = [
|
||||
@ -108,73 +107,73 @@ const appRoutes1: IqserRoute[] = [
|
||||
permissions: {
|
||||
allow: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
|
||||
if (route.params['id'] === 42) {
|
||||
return ['MANAGER', "UTILS"]
|
||||
return ['MANAGER', 'UTILS'];
|
||||
} else {
|
||||
return 'ADMIN'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'ADMIN';
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const appRoutes2: IqserRoute[] = [
|
||||
{
|
||||
path: "home",
|
||||
path: 'home',
|
||||
component: HomeComponent,
|
||||
canActivate: [IqserPermissionsGuard],
|
||||
data: {
|
||||
permissions: {
|
||||
allow: ["ADMIN", "MODERATOR"],
|
||||
allow: ['ADMIN', 'MODERATOR'],
|
||||
redirectTo: {
|
||||
navigationCommands: ["123"],
|
||||
navigationCommands: ['123'],
|
||||
navigationExtras: {
|
||||
skipLocationChange: true
|
||||
}
|
||||
}
|
||||
}
|
||||
skipLocationChange: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
const appRoutes3: IqserRoute[] = [
|
||||
{
|
||||
path: "home",
|
||||
path: 'home',
|
||||
component: HomeComponent,
|
||||
canActivate: [IqserPermissionsGuard],
|
||||
data: {
|
||||
permissions: {
|
||||
allow: ["canReadAgenda", "canEditAgenda"],
|
||||
allow: ['canReadAgenda', 'canEditAgenda'],
|
||||
redirectTo: {
|
||||
canReadAgenda: "agendaList",
|
||||
canEditAgenda: "dashboard",
|
||||
default: "login"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
canReadAgenda: 'agendaList',
|
||||
canEditAgenda: 'dashboard',
|
||||
default: 'login',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const appRoutes4: IqserRoute[] = [
|
||||
{
|
||||
path: "home",
|
||||
path: 'home',
|
||||
component: HomeComponent,
|
||||
canActivate: [IqserPermissionsGuard],
|
||||
data: {
|
||||
permissions: {
|
||||
allow: ["canEditAgenda"],
|
||||
allow: ['canEditAgenda'],
|
||||
redirectTo: {
|
||||
canEditAgenda: {
|
||||
navigationCommands: "dashboard",
|
||||
navigationCommands: 'dashboard',
|
||||
navigationExtras: {
|
||||
skipLocationChange: true
|
||||
}
|
||||
skipLocationChange: true,
|
||||
},
|
||||
},
|
||||
default: 'login',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
default: "login"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const appRoutes5: IqserRoute[] = [
|
||||
@ -186,22 +185,29 @@ const appRoutes5: IqserRoute[] = [
|
||||
permissions: {
|
||||
allow: ['canReadAgenda', 'canEditAgenda'],
|
||||
redirectTo: {
|
||||
canReadAgenda: (rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routeStateSnapshot: RouterStateSnapshot) => {
|
||||
canReadAgenda: (
|
||||
rejectedPermissionName: string,
|
||||
activateRouteSnapshot: ActivatedRouteSnapshot,
|
||||
routeStateSnapshot: RouterStateSnapshot,
|
||||
) => {
|
||||
return 'dashboard';
|
||||
},
|
||||
canEditAgenda: (rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routeStateSnapshot: RouterStateSnapshot) => {
|
||||
canEditAgenda: (
|
||||
rejectedPermissionName: string,
|
||||
activateRouteSnapshot: ActivatedRouteSnapshot,
|
||||
routeStateSnapshot: RouterStateSnapshot,
|
||||
) => {
|
||||
return {
|
||||
navigationCommands: ['/dashboard'],
|
||||
navigationExtras: {
|
||||
skipLocationChange: true
|
||||
}
|
||||
}
|
||||
skipLocationChange: true,
|
||||
},
|
||||
};
|
||||
},
|
||||
default: 'login',
|
||||
},
|
||||
},
|
||||
},
|
||||
default: 'login'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
```
|
||||
|
||||
@ -291,7 +291,7 @@ describe('Permission directive angular testing different async functions in role
|
||||
}));
|
||||
|
||||
it('should hide the component when one returns falsy value', fakeAsync(() => {
|
||||
let content = getFixtureContent();
|
||||
const content = getFixtureContent();
|
||||
expect(content).toBeTruthy();
|
||||
expect(content.innerHTML).toEqual('<div>123</div>');
|
||||
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<ng-container *ngIf="type$ | async as type">
|
||||
@if (type$ | async; as type) {
|
||||
<ng-container *ngTemplateOutlet="templates[type]"></ng-container>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, HostBinding, inject, Input, TemplateRef } from '@angular/core';
|
||||
import { SkeletonService } from '../../services';
|
||||
import { IqserUserService } from '../../users';
|
||||
import { AsyncPipe, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common';
|
||||
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
|
||||
import { tap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
@ -10,7 +10,7 @@ import { tap } from 'rxjs/operators';
|
||||
styleUrls: ['./skeleton.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [NgTemplateOutlet, NgIf, AsyncPipe, NgForOf],
|
||||
imports: [NgTemplateOutlet, AsyncPipe],
|
||||
})
|
||||
export class SkeletonComponent {
|
||||
@Input() templates!: Record<string, TemplateRef<unknown>>;
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
<div [ngClass]="{ small: small }" class="rectangle-container">
|
||||
<div *ngFor="let config of configs" [style]="'flex: ' + (config.length || 1) + ';'" class="section-wrapper">
|
||||
@for (config of configs; track config) {
|
||||
<div [style]="'flex: ' + (config.length || 1) + ';'" class="section-wrapper">
|
||||
<div
|
||||
[className]="'rectangle ' + config.color"
|
||||
[ngStyle]="{
|
||||
'background-color': config.color.includes('#') ? config.color : '',
|
||||
}"
|
||||
></div>
|
||||
|
||||
<div *ngIf="config.label" [class]="config.cssClass + ' clamp-1'" [matTooltip]="config.label" matTooltipPosition="above">
|
||||
@if (config.label) {
|
||||
<div [class]="config.cssClass + ' clamp-1'" [matTooltip]="config.label" matTooltipPosition="above">
|
||||
{{ config.label }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
|
||||
import { StatusBarConfig } from './status-bar-config.model';
|
||||
import { NgClass, NgForOf, NgIf, NgStyle } from '@angular/common';
|
||||
import { NgClass, NgStyle } from '@angular/common';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
|
||||
@Component({
|
||||
@ -10,7 +10,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [NgClass, NgStyle, NgForOf, MatTooltipModule, NgIf],
|
||||
imports: [NgClass, NgStyle, MatTooltipModule],
|
||||
})
|
||||
export class StatusBarComponent<T extends string> {
|
||||
@Input() configs: readonly StatusBarConfig<T>[] = [];
|
||||
|
||||
@ -1,23 +1,35 @@
|
||||
<div class="row">
|
||||
<div *ngIf="title" [attr.aria-label]="title" [class]="options.titleClass">
|
||||
@if (title) {
|
||||
<div [attr.aria-label]="title" [class]="options.titleClass">
|
||||
{{ title }}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div *ngIf="message && options.enableHtml" [class]="options.messageClass" [innerHTML]="message" aria-live="polite" role="alert"></div>
|
||||
@if (message && options.enableHtml) {
|
||||
<div [class]="options.messageClass" [innerHTML]="message" aria-live="polite" role="alert"></div>
|
||||
}
|
||||
|
||||
<div *ngIf="message && !options.enableHtml" [attr.aria-label]="message" [class]="options.messageClass" aria-live="polite" role="alert">
|
||||
@if (message && !options.enableHtml) {
|
||||
<div [attr.aria-label]="message" [class]="options.messageClass" aria-live="polite" role="alert">
|
||||
{{ message }}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div *ngIf="actions?.length" class="actions-wrapper">
|
||||
<a (click)="callAction(action.action)" *ngFor="let action of actions" iqserStopPropagation>
|
||||
@if (actions?.length) {
|
||||
<div class="actions-wrapper">
|
||||
@for (action of actions; track action) {
|
||||
<a (click)="callAction(action.action)" iqserStopPropagation>
|
||||
{{ action.title }}
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="text-right">
|
||||
<a (click)="remove()" *ngIf="options.closeButton" class="toast-close-button">
|
||||
@if (options.closeButton) {
|
||||
<a (click)="remove()" class="toast-close-button">
|
||||
<mat-icon svgIcon="iqser:close"></mat-icon>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -2,14 +2,14 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { Toast } from 'ngx-toastr';
|
||||
import { ToasterActions, ToasterOptions } from '../../services';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { NgForOf, NgIf } from '@angular/common';
|
||||
|
||||
import { StopPropagationDirective } from '../../directives';
|
||||
|
||||
@Component({
|
||||
templateUrl: './toast.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [MatIconModule, NgIf, StopPropagationDirective, NgForOf],
|
||||
imports: [MatIconModule, StopPropagationDirective],
|
||||
})
|
||||
export class ToastComponent extends Toast {
|
||||
get actions(): ToasterActions[] {
|
||||
|
||||
@ -8,38 +8,40 @@
|
||||
|
||||
<iqser-spacer [height]="100"></iqser-spacer>
|
||||
|
||||
<ng-container *ngIf="isLoggedOut || noRoleLogOut">
|
||||
@if (isLoggedOut || noRoleLogOut) {
|
||||
<div class="heading-xl" [translate]="isLoggedOut ? translations.IS_LOGGED_OUT : translations.NO_ROLE_LOG_OUT"></div>
|
||||
<iqser-spacer [height]="75"></iqser-spacer>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
<div *ngIf="storedTenants.length" class="pb-30 subheading" translate="tenant-resolve.header.sign-in-previous-domain"></div>
|
||||
@if (storedTenants.length) {
|
||||
<div class="pb-30 subheading" translate="tenant-resolve.header.sign-in-previous-domain"></div>
|
||||
}
|
||||
|
||||
<div *ngIf="storedTenants.length">
|
||||
<div
|
||||
(click)="select(stored.tenantId)"
|
||||
*ngFor="let stored of storedTenants"
|
||||
class="d-flex pointer mat-elevation-z2 card stored-tenant-card mt-10"
|
||||
>
|
||||
@if (storedTenants.length) {
|
||||
<div>
|
||||
@for (stored of storedTenants; track stored) {
|
||||
<div (click)="select(stored.tenantId)" class="d-flex pointer mat-elevation-z2 card stored-tenant-card mt-10">
|
||||
<iqser-logo class="card-icon" icon="iqser:logo" mat-card-image></iqser-logo>
|
||||
|
||||
<div class="card-content flex-column">
|
||||
<span class="heading">{{ stored.tenantId }}</span>
|
||||
</div>
|
||||
|
||||
<mat-icon class="card-icon upside-down" svgIcon="iqser:expand"></mat-icon>
|
||||
<div class="remove" iqserStopPropagation>
|
||||
<mat-icon (click)="removeStored(stored.tenantId)" svgIcon="iqser:close"></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div *ngIf="storedTenants.length === 0" class="heading pb-30" translate="tenant-resolve.header.first-time"></div>
|
||||
@if (storedTenants.length === 0) {
|
||||
<div class="heading pb-30" translate="tenant-resolve.header.first-time"></div>
|
||||
}
|
||||
|
||||
<ng-container *ngIf="storedTenants.length">
|
||||
@if (storedTenants.length) {
|
||||
<iqser-spacer [height]="100"></iqser-spacer>
|
||||
<div class="pb-30 subheading" translate="tenant-resolve.header.join-another-domain"></div>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
<form (submit)="updateTenantSelection()" [formGroup]="form" class="mat-elevation-z16 card input-card d-flex">
|
||||
<mat-form-field class="iqser-input-group w-full ml-20">
|
||||
|
||||
@ -1,22 +1,25 @@
|
||||
<div (click)="triggerAttachFile()" (fileDropped)="attachFile($event)" *ngIf="!file" class="upload-area" iqserDragDropFileUpload>
|
||||
@if (!file) {
|
||||
<div (click)="triggerAttachFile()" (fileDropped)="attachFile($event)" class="upload-area" iqserDragDropFileUpload>
|
||||
<mat-icon svgIcon="iqser:upload"></mat-icon>
|
||||
|
||||
<div translate="upload-file.upload-area-text"></div>
|
||||
</div>
|
||||
<div *ngIf="file" class="file-area">
|
||||
</div>
|
||||
}
|
||||
@if (file) {
|
||||
<div class="file-area">
|
||||
<mat-icon svgIcon="iqser:document"></mat-icon>
|
||||
|
||||
<p>{{ file.name }}</p>
|
||||
|
||||
<mat-icon (click)="removeFile()" *ngIf="!readonly" svgIcon="iqser:trash"></mat-icon>
|
||||
</div>
|
||||
@if (!readonly) {
|
||||
<mat-icon (click)="removeFile()" svgIcon="iqser:trash"></mat-icon>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<input
|
||||
#attachFileInput
|
||||
id="file-upload-input"
|
||||
(change)="attachFile($event)"
|
||||
[accept]="accept"
|
||||
[hidden]="true"
|
||||
class="file-upload-input"
|
||||
id="file-upload-input"
|
||||
type="file"
|
||||
/>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<div *ngIf="_user && _user | name: namePipeOptions as userName" class="wrapper">
|
||||
@if (_user && _user | name: namePipeOptions; as userName) {
|
||||
<div class="wrapper">
|
||||
<div
|
||||
[className]="colorClass + ' oval ' + size + (hasBorder ? ' border' : '')"
|
||||
[matTooltipPosition]="tooltipPosition"
|
||||
@ -6,8 +7,10 @@
|
||||
>
|
||||
{{ _user | name: { showInitials: true } }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="withName" [class.disabled]="disabled" class="clamp-1 username" id="avatarUsername">
|
||||
@if (withName) {
|
||||
<div [class.disabled]="disabled" class="clamp-1 username" id="avatarUsername">
|
||||
{{ userName }}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -1,14 +1,18 @@
|
||||
<button [class.overlay]="showDot" [matTooltipPosition]="'below'" [matTooltip]="'user-menu.button-text' | translate" mat-button>
|
||||
<ng-container *ngIf="icon; else initialsAvatar">
|
||||
@if (icon) {
|
||||
<ng-container>
|
||||
<mat-icon [svgIcon]="icon" class="mr-8"></mat-icon>
|
||||
{{ userService.currentUser$ | async | name }}
|
||||
</ng-container>
|
||||
} @else {
|
||||
<iqser-initials-avatar [showTooltip]="false" [user]="userService.currentUser$ | async" [withName]="true"></iqser-initials-avatar>
|
||||
}
|
||||
|
||||
<mat-icon *ngIf="showDropdownArrow" iconPositionEnd svgIcon="iqser:arrow-down"></mat-icon>
|
||||
@if (showDropdownArrow) {
|
||||
<mat-icon iconPositionEnd svgIcon="iqser:arrow-down"></mat-icon>
|
||||
}
|
||||
</button>
|
||||
|
||||
<div *ngIf="showDot" class="dot"></div>
|
||||
|
||||
<ng-template #initialsAvatar>
|
||||
<iqser-initials-avatar [showTooltip]="false" [user]="userService.currentUser$ | async" [withName]="true"></iqser-initials-avatar>
|
||||
</ng-template>
|
||||
@if (showDot) {
|
||||
<div class="dot"></div>
|
||||
}
|
||||
|
||||
@ -5,5 +5,5 @@
|
||||
"types": ["jest", "node"],
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["./src/lib/**/*.spec.ts", "./src/lib/**/*.d.ts"]
|
||||
"include": ["./src/lib/**/*.spec.ts", "./src/lib/**/*.d.ts", "jest.config.ts"]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user