unfuck circular imports
This commit is contained in:
parent
04ae68891c
commit
d595a22db1
@ -1,4 +1,4 @@
|
||||
import { List } from '../utils';
|
||||
import { List } from '../utils/types/iqser-types';
|
||||
|
||||
export interface DynamicCache {
|
||||
readonly urls: List;
|
||||
|
||||
@ -3,12 +3,13 @@ import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { debounceTime, firstValueFrom, fromEvent, merge, of, Subscription } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { ConfirmOptions } from '.';
|
||||
import { IconButtonTypes } from '../buttons';
|
||||
import { LoadingService } from '../loading';
|
||||
import { Toaster } from '../services';
|
||||
import { hasFormChanged, IqserEventTarget } from '../utils';
|
||||
import { IconButtonTypes } from '../buttons/types/icon-button.type';
|
||||
import { LoadingService } from '../loading/loading.service';
|
||||
import { Toaster } from '../services/toaster.service';
|
||||
import { hasFormChanged } from '../utils/functions';
|
||||
import { IqserEventTarget } from '../utils/types/events.type';
|
||||
import { ConfirmationDialogService } from './confirmation-dialog.service';
|
||||
import { ConfirmOptions } from './confirmation-dialog/confirmation-dialog.component';
|
||||
|
||||
const DIALOG_CONTAINER = 'mat-dialog-container';
|
||||
const TEXT_INPUT = 'text';
|
||||
@ -21,16 +22,16 @@ export interface SaveOptions {
|
||||
|
||||
@Directive()
|
||||
export abstract class BaseDialogComponent implements AfterViewInit, OnDestroy {
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
form?: UntypedFormGroup;
|
||||
initialFormValue!: Record<string, string>;
|
||||
readonly #confirmationDialogService = inject(ConfirmationDialogService);
|
||||
readonly #dialog = inject(MatDialog);
|
||||
protected readonly _hasErrors = signal(true);
|
||||
protected readonly _formBuilder = inject(UntypedFormBuilder);
|
||||
protected readonly _loadingService = inject(LoadingService);
|
||||
protected readonly _toaster = inject(Toaster);
|
||||
protected readonly _subscriptions = new Subscription();
|
||||
readonly #confirmationDialogService = inject(ConfirmationDialogService);
|
||||
readonly #dialog = inject(MatDialog);
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
form?: UntypedFormGroup;
|
||||
initialFormValue!: Record<string, string>;
|
||||
|
||||
protected constructor(
|
||||
protected readonly _dialogRef: MatDialogRef<BaseDialogComponent>,
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { ConfirmationDialogComponent, ConfirmOption, defaultDialogConfig, IConfirmationDialogData, TitleColors } from '.';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import {
|
||||
ConfirmationDialogComponent,
|
||||
ConfirmOption,
|
||||
IConfirmationDialogData,
|
||||
TitleColors,
|
||||
} from './confirmation-dialog/confirmation-dialog.component';
|
||||
import { defaultDialogConfig } from './dialog.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
|
||||
@ -6,8 +6,10 @@ import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/materia
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { CircleButtonComponent, IconButtonComponent, IconButtonTypes } from '../../buttons';
|
||||
import { ValuesOf } from '../../utils';
|
||||
import { CircleButtonComponent } from '../../buttons/circle-button/circle-button.component';
|
||||
import { IconButtonComponent } from '../../buttons/icon-button/icon-button.component';
|
||||
import { IconButtonTypes } from '../../buttons/types/icon-button.type';
|
||||
import { ValuesOf } from '../../utils/types/utility-types';
|
||||
|
||||
export const TitleColors = {
|
||||
DEFAULT: 'default',
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog';
|
||||
import { ComponentType } from '@angular/cdk/portal';
|
||||
import { mergeMap } from 'rxjs/operators';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog';
|
||||
import { from } from 'rxjs';
|
||||
import { mergeMap } from 'rxjs/operators';
|
||||
|
||||
export const largeDialogConfig: MatDialogConfig = {
|
||||
width: '90vw',
|
||||
@ -64,4 +64,34 @@ export abstract class DialogService<T extends string> {
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
open(
|
||||
type: Type<unknown>,
|
||||
data?: unknown,
|
||||
config?: object,
|
||||
cb?: (...params: unknown[]) => Promise<unknown> | void,
|
||||
finallyCb?: (...params: unknown[]) => void | Promise<unknown>,
|
||||
): MatDialogRef<unknown> {
|
||||
const ref = this._dialog.open(type, {
|
||||
...defaultDialogConfig,
|
||||
...(config || {}),
|
||||
data,
|
||||
});
|
||||
|
||||
const fn = async (result: unknown) => {
|
||||
if (result && cb) {
|
||||
await cb(result);
|
||||
}
|
||||
|
||||
if (finallyCb) {
|
||||
await finallyCb(result);
|
||||
}
|
||||
};
|
||||
|
||||
ref.afterClosed()
|
||||
.pipe(mergeMap(result => from(fn(result))))
|
||||
.subscribe();
|
||||
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { Directive, HostListener, inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { hasFormChanged, IqserEventTarget } from '../utils';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { IconButtonTypes } from '../buttons';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { IconButtonTypes } from '../buttons/types/icon-button.type';
|
||||
import { hasFormChanged } from '../utils/functions';
|
||||
import { IqserEventTarget } from '../utils/types/events.type';
|
||||
|
||||
const DIALOG_CONTAINER = 'mat-dialog-container';
|
||||
const DATA_TYPE_SYMBOL = Symbol.for('DATA_TYPE');
|
||||
|
||||
@ -1,21 +1,20 @@
|
||||
import { AsyncPipe, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, Input, OnInit, TemplateRef } from '@angular/core';
|
||||
import { MAT_CHECKBOX_DEFAULT_OPTIONS, MatCheckbox } from '@angular/material/checkbox';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { combineLatest, Observable, pipe } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { StopPropagationDirective } from '../../directives/stop-propagation.directive';
|
||||
import { InputWithActionComponent } from '../../inputs/input-with-action/input-with-action.component';
|
||||
import { SearchService } from '../../search/search.service';
|
||||
import { shareDistinctLast, shareLast } from '../../utils/operators';
|
||||
import { FilterService } from '../filter.service';
|
||||
import { Filter } from '../models/filter';
|
||||
import { IFilterGroup } from '../models/filter-group.model';
|
||||
import { IFilter } from '../models/filter.model';
|
||||
import { INestedFilter } from '../models/nested-filter.model';
|
||||
import { IFilterGroup } from '../models/filter-group.model';
|
||||
import { extractFilterValues, handleCheckedValue } from '../filter-utils';
|
||||
import { FilterService } from '../filter.service';
|
||||
import { SearchService } from '../../search';
|
||||
import { Filter } from '../models/filter';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { shareDistinctLast, shareLast } from '../../utils';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { MAT_CHECKBOX_DEFAULT_OPTIONS, MatCheckbox } from '@angular/material/checkbox';
|
||||
import { AsyncPipe, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common';
|
||||
import { InputWithActionComponent } from '../../inputs';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { StopPropagationDirective } from '../../directives';
|
||||
|
||||
const areExpandable = (nestedFilter: INestedFilter) => !!nestedFilter?.children?.length;
|
||||
const atLeastOneIsExpandable = pipe(
|
||||
@ -23,17 +22,6 @@ const atLeastOneIsExpandable = pipe(
|
||||
shareDistinctLast(),
|
||||
);
|
||||
|
||||
export interface LocalStorageFilter {
|
||||
id: string;
|
||||
checked: boolean;
|
||||
children?: LocalStorageFilter[] | null;
|
||||
}
|
||||
|
||||
export interface LocalStorageFilters {
|
||||
primaryFilters: LocalStorageFilter[] | null;
|
||||
secondaryFilters: LocalStorageFilter[] | null;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-filter-card [primaryFiltersSlug]',
|
||||
templateUrl: './filter-card.component.html',
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { INestedFilter } from './models/nested-filter.model';
|
||||
import { IListable } from '../listing/models/listable';
|
||||
import { Id } from '../listing/models/trackable';
|
||||
import { IFilterGroup } from './models/filter-group.model';
|
||||
import { IFilter } from './models/filter.model';
|
||||
import { LocalStorageFilter } from './models/local-filters.model';
|
||||
import { NestedFilter } from './models/nested-filter';
|
||||
import { Id, IListable } from '../listing';
|
||||
import { LocalStorageFilter } from './filter-card/filter-card.component';
|
||||
import { INestedFilter } from './models/nested-filter.model';
|
||||
|
||||
function copySettings(oldFilters: INestedFilter[], newFilters: INestedFilter[]) {
|
||||
if (!oldFilters || !newFilters) {
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import { map, startWith, switchMap } from 'rxjs/operators';
|
||||
import { extractFilterValues, handleCheckedValue, processFilters, toFlatFilters } from './filter-utils';
|
||||
import { IFilterGroup } from './models/filter-group.model';
|
||||
import { INestedFilter } from './models/nested-filter.model';
|
||||
import { get, shareDistinctLast, shareLast, some } from '../utils';
|
||||
import { NestedFilter } from './models/nested-filter';
|
||||
import { extractFilterValues, handleCheckedValue, processFilters, toFlatFilters } from './filter-utils';
|
||||
import { Filter } from './models/filter';
|
||||
import { IFilterGroup } from './models/filter-group.model';
|
||||
import { IFilter } from './models/filter.model';
|
||||
import { LocalStorageFilters } from './filter-card/filter-card.component';
|
||||
import { LocalStorageFilters } from './models/local-filters.model';
|
||||
import { NestedFilter } from './models/nested-filter';
|
||||
import { INestedFilter } from './models/nested-filter.model';
|
||||
|
||||
export interface CheckboxClickedParams {
|
||||
nestedFilter: INestedFilter;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { IListable } from '../../listing/models/listable';
|
||||
import { IFilter } from './filter.model';
|
||||
import { IListable } from '../../listing';
|
||||
|
||||
export class Filter implements IFilter, IListable {
|
||||
readonly id: string;
|
||||
|
||||
10
src/lib/filtering/models/local-filters.model.ts
Normal file
10
src/lib/filtering/models/local-filters.model.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export interface LocalStorageFilter {
|
||||
id: string;
|
||||
checked: boolean;
|
||||
children?: LocalStorageFilter[] | null;
|
||||
}
|
||||
|
||||
export interface LocalStorageFilters {
|
||||
primaryFilters: LocalStorageFilter[] | null;
|
||||
secondaryFilters: LocalStorageFilter[] | null;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { IListable } from '../../listing';
|
||||
import { IListable } from '../../listing/models/listable';
|
||||
import { Filter } from './filter';
|
||||
import { INestedFilter } from './nested-filter.model';
|
||||
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
import { AsyncPipe, NgIf } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit, TemplateRef } from '@angular/core';
|
||||
import { MatMenu, MatMenuContent, MatMenuTrigger } from '@angular/material/menu';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
|
||||
import { delay, map } from 'rxjs/operators';
|
||||
import { shareDistinctLast, shareLast, some } from '../../utils';
|
||||
import { ChevronButtonComponent } from '../../buttons/chevron-button/chevron-button.component';
|
||||
import { IconButtonComponent } from '../../buttons/icon-button/icon-button.component';
|
||||
import { StopPropagationDirective } from '../../directives/stop-propagation.directive';
|
||||
import { shareDistinctLast, shareLast, some } from '../../utils/operators';
|
||||
import { FilterCardComponent } from '../filter-card/filter-card.component';
|
||||
import { FilterService } from '../filter.service';
|
||||
import { IFilterGroup } from '../models/filter-group.model';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { ChevronButtonComponent, IconButtonComponent } from '../../buttons';
|
||||
import { AsyncPipe, NgIf } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatMenu, MatMenuContent, MatMenuTrigger } from '@angular/material/menu';
|
||||
import { FilterCardComponent } from '../filter-card/filter-card.component';
|
||||
import { StopPropagationDirective } from '../../directives';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-popup-filter [primaryFiltersSlug]',
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/* eslint-disable @angular-eslint/prefer-on-push-component-change-detection */
|
||||
import { AfterViewInit, Component, ElementRef, HostListener, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { HelpModeService } from '../index';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { HelpModeService } from '../help-mode.service';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-help-button',
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
import { Inject, Injectable, Renderer2, RendererFactory2 } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { BehaviorSubject, firstValueFrom } from 'rxjs';
|
||||
import { getConfig } from '../services/iqser-config.service';
|
||||
import { IqserUserPreferenceService } from '../services/iqser-user-preference.service';
|
||||
import { HelpModeDialogComponent } from './help-mode-dialog/help-mode-dialog.component';
|
||||
import { HELP_MODE_KEYS, MANUAL_BASE_URL } from './tokens';
|
||||
import { HelpModeKey } from './types';
|
||||
import {
|
||||
DOCUMINE_THEME_CLASS,
|
||||
HELP_HIGHLIGHT_CLASS,
|
||||
@ -16,8 +20,6 @@ import {
|
||||
ScrollableParentViews,
|
||||
WEB_VIEWER_ELEMENTS,
|
||||
} from './utils/constants';
|
||||
import { getConfig, IqserUserPreferenceService } from '../services';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
||||
export interface Helper {
|
||||
readonly element: HTMLElement;
|
||||
@ -28,24 +30,16 @@ export interface Helper {
|
||||
readonly iframeElement?: boolean;
|
||||
}
|
||||
|
||||
export interface HelpModeKey {
|
||||
readonly elementKey: string;
|
||||
readonly documentKey: string;
|
||||
readonly scrollableParentView?: ScrollableParentView;
|
||||
readonly overlappingElements?: OverlappingElement[];
|
||||
readonly dialogElement?: boolean;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class HelpModeService {
|
||||
readonly #isHelpModeActive$ = new BehaviorSubject(false);
|
||||
readonly isHelpModeActive$ = this.#isHelpModeActive$.asObservable();
|
||||
readonly #helpModeDialogIsOpened$ = new BehaviorSubject(false);
|
||||
readonly helpModeDialogIsOpened$ = this.#helpModeDialogIsOpened$.asObservable();
|
||||
readonly #renderer: Renderer2;
|
||||
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
||||
#helpers: Record<string, Helper> = {};
|
||||
#dialogMode = false;
|
||||
readonly isHelpModeActive$ = this.#isHelpModeActive$.asObservable();
|
||||
readonly helpModeDialogIsOpened$ = this.#helpModeDialogIsOpened$.asObservable();
|
||||
|
||||
constructor(
|
||||
@Inject(HELP_MODE_KEYS) private readonly _keys: HelpModeKey[],
|
||||
@ -106,6 +100,19 @@ export class HelpModeService {
|
||||
}
|
||||
}
|
||||
|
||||
highlightHelperElements(): void {
|
||||
Object.values(this.#helpers).forEach(helper => {
|
||||
this.#renderer.addClass(helper.helperElement, HELP_HIGHLIGHT_CLASS);
|
||||
setTimeout(() => {
|
||||
this.#renderer.removeClass(helper.helperElement, HELP_HIGHLIGHT_CLASS);
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
updateHelperElements() {
|
||||
Object.values(this.#helpers).forEach(helper => this.#updateHelperElement(helper));
|
||||
}
|
||||
|
||||
#createHelpers() {
|
||||
for (const key of Object.values(this._keys)) {
|
||||
const elements = document.querySelectorAll(`[help-mode-key='${key.elementKey}']`);
|
||||
@ -159,19 +166,6 @@ export class HelpModeService {
|
||||
return `${this._manualBaseURL}/${currentLang}/index-${currentLang}.html?contextId=${key}`;
|
||||
}
|
||||
|
||||
highlightHelperElements(): void {
|
||||
Object.values(this.#helpers).forEach(helper => {
|
||||
this.#renderer.addClass(helper.helperElement, HELP_HIGHLIGHT_CLASS);
|
||||
setTimeout(() => {
|
||||
this.#renderer.removeClass(helper.helperElement, HELP_HIGHLIGHT_CLASS);
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
updateHelperElements() {
|
||||
Object.values(this.#helpers).forEach(helper => this.#updateHelperElement(helper));
|
||||
}
|
||||
|
||||
#isElementVisible(helper: Helper): boolean {
|
||||
if (helper.iframeElement && !this.#isFilePreviewPage()) {
|
||||
return false;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { inject, InjectionToken } from '@angular/core';
|
||||
import { IqserConfigService } from '../services';
|
||||
import { HelpModeKey } from './help-mode.service';
|
||||
import { IqserConfigService } from '../services/iqser-config.service';
|
||||
import { HelpModeKey } from './types';
|
||||
|
||||
export const HELP_MODE_KEYS = new InjectionToken<HelpModeKey>('Help mode keys');
|
||||
export const MANUAL_BASE_URL = new InjectionToken<string>('Base manual URL', {
|
||||
|
||||
9
src/lib/help-mode/types.ts
Normal file
9
src/lib/help-mode/types.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { OverlappingElement, ScrollableParentView } from './utils/constants';
|
||||
|
||||
export interface HelpModeKey {
|
||||
readonly elementKey: string;
|
||||
readonly documentKey: string;
|
||||
readonly scrollableParentView?: ScrollableParentView;
|
||||
readonly overlappingElements?: OverlappingElement[];
|
||||
readonly dialogElement?: boolean;
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import { HelpModeKey, HelpModeService } from '../help-mode.service';
|
||||
import { HelpModeService } from '../help-mode.service';
|
||||
import { HELP_MODE_KEYS } from '../tokens';
|
||||
import { HelpModeKey } from '../types';
|
||||
|
||||
export function provideHelpMode(helpModeKeys: HelpModeKey[]) {
|
||||
return [{ provide: HELP_MODE_KEYS, useValue: helpModeKeys }, HelpModeService];
|
||||
|
||||
@ -1,12 +1,16 @@
|
||||
import { Directive, inject, OnDestroy, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { FilterService } from '../filtering';
|
||||
import { SortingService } from '../sorting';
|
||||
import { AutoUnsubscribe, shareDistinctLast } from '../utils';
|
||||
import { SearchService } from '../search';
|
||||
import { EntitiesService, ListingService } from './services';
|
||||
import { Id, IListable, TableColumnConfig } from './models';
|
||||
import { FilterService } from '../filtering/filter.service';
|
||||
import { SearchService } from '../search/search.service';
|
||||
import { SortingService } from '../sorting/sorting.service';
|
||||
import { AutoUnsubscribe } from '../utils/auto-unsubscribe.directive';
|
||||
import { shareDistinctLast } from '../utils/operators';
|
||||
import { IListable } from './models/listable';
|
||||
import { TableColumnConfig } from './models/table-column-config.model';
|
||||
import { Id } from './models/trackable';
|
||||
import { EntitiesService } from './services/entities.service';
|
||||
import { ListingService } from './services/listing.service';
|
||||
|
||||
@Directive()
|
||||
export abstract class ListingComponent<Class extends IListable<PrimaryKey>, PrimaryKey extends Id = Class['id']>
|
||||
|
||||
@ -1,48 +1,55 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { TableHeaderComponent } from './table-header/table-header.component';
|
||||
import { IqserFiltersModule, PopupFilterComponent } from '../filtering';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TableColumnNameComponent } from './table-column-name/table-column-name.component';
|
||||
import { ScrollButtonComponent } from './scroll-button/scroll-button.component';
|
||||
import { TableComponent } from './table/table.component';
|
||||
import { HasScrollbarDirective, SyncWidthDirective } from '../directives';
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { WorkflowComponent } from './workflow/workflow.component';
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { PageHeaderComponent } from './page-header/page-header.component';
|
||||
import { TableContentComponent } from './table-content/table-content.component';
|
||||
import { TableItemComponent } from './table-content/table-item/table-item.component';
|
||||
import { ColumnHeaderComponent } from './workflow/column-header/column-header.component';
|
||||
import { CircleButtonComponent, IconButtonComponent } from '../buttons';
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CircleButtonComponent, IconButtonComponent } from '../buttons';
|
||||
import { HasScrollbarDirective, SyncWidthDirective } from '../directives';
|
||||
import { EmptyStateComponent } from '../empty-state';
|
||||
import { IqserFiltersModule, PopupFilterComponent } from '../filtering';
|
||||
import { InputWithActionComponent, RoundCheckboxComponent } from '../inputs';
|
||||
import { SnakeCasePipe } from '../pipes/snake-case.pipe';
|
||||
import { PageHeaderComponent } from './page-header/page-header.component';
|
||||
import { ScrollButtonComponent } from './scroll-button/scroll-button.component';
|
||||
import { TableColumnNameComponent } from './table-column-name/table-column-name.component';
|
||||
import { TableContentComponent } from './table-content/table-content.component';
|
||||
import { TableItemComponent } from './table-content/table-item/table-item.component';
|
||||
import { TableHeaderComponent } from './table-header/table-header.component';
|
||||
import { TableComponent } from './table/table.component';
|
||||
import { ColumnHeaderComponent } from './workflow/column-header/column-header.component';
|
||||
import { WorkflowComponent } from './workflow/workflow.component';
|
||||
|
||||
const matModules = [MatTooltipModule, MatIconModule];
|
||||
const components = [
|
||||
TableHeaderComponent,
|
||||
TableComponent,
|
||||
WorkflowComponent,
|
||||
TableColumnNameComponent,
|
||||
ScrollButtonComponent,
|
||||
PageHeaderComponent,
|
||||
TableContentComponent,
|
||||
TableItemComponent,
|
||||
ColumnHeaderComponent,
|
||||
];
|
||||
const modules = [DragDropModule, TranslateModule, IqserFiltersModule, ScrollingModule, RouterModule];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components],
|
||||
exports: [...components],
|
||||
exports: [
|
||||
WorkflowComponent,
|
||||
ScrollButtonComponent,
|
||||
PageHeaderComponent,
|
||||
TableContentComponent,
|
||||
TableColumnNameComponent,
|
||||
TableHeaderComponent,
|
||||
TableComponent,
|
||||
ColumnHeaderComponent,
|
||||
TableItemComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
...modules,
|
||||
...matModules,
|
||||
WorkflowComponent,
|
||||
ScrollButtonComponent,
|
||||
PageHeaderComponent,
|
||||
TableColumnNameComponent,
|
||||
TableContentComponent,
|
||||
TableComponent,
|
||||
TableItemComponent,
|
||||
ColumnHeaderComponent,
|
||||
TableHeaderComponent,
|
||||
CircleButtonComponent,
|
||||
IconButtonComponent,
|
||||
EmptyStateComponent,
|
||||
|
||||
@ -1,18 +1,37 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Optional, Output, TemplateRef } from '@angular/core';
|
||||
import { ActionConfig, ButtonConfig, SearchPosition, SearchPositions } from './models';
|
||||
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, inject, Input, Output, TemplateRef } from '@angular/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import { IListable } from '../models';
|
||||
import { IconButtonTypes } from '../../buttons';
|
||||
import { SearchService } from '../../search';
|
||||
import { FilterService } from '../../filtering';
|
||||
import { filterEach, List } from '../../utils';
|
||||
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||
import { CircleButtonComponent } from '../../buttons/circle-button/circle-button.component';
|
||||
import { IconButtonComponent } from '../../buttons/icon-button/icon-button.component';
|
||||
import { IconButtonTypes } from '../../buttons/types/icon-button.type';
|
||||
import { FilterService } from '../../filtering/filter.service';
|
||||
import { IqserFiltersModule } from '../../filtering/filters.module';
|
||||
import { PopupFilterComponent } from '../../filtering/popup-filter/popup-filter.component';
|
||||
import { InputWithActionComponent } from '../../inputs/input-with-action/input-with-action.component';
|
||||
import { SearchService } from '../../search/search.service';
|
||||
import { filterEach } from '../../utils/operators';
|
||||
import { List } from '../../utils/types/iqser-types';
|
||||
import { IListable } from '../models/listable';
|
||||
import { ActionConfig, ButtonConfig, SearchPosition, SearchPositions } from './models';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-page-header',
|
||||
templateUrl: './page-header.component.html',
|
||||
styleUrls: ['./page-header.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [
|
||||
AsyncPipe,
|
||||
NgTemplateOutlet,
|
||||
PopupFilterComponent,
|
||||
IqserFiltersModule,
|
||||
IconButtonComponent,
|
||||
CircleButtonComponent,
|
||||
TranslateModule,
|
||||
InputWithActionComponent,
|
||||
],
|
||||
})
|
||||
export class PageHeaderComponent<T extends IListable> {
|
||||
readonly searchPositions = SearchPositions;
|
||||
@ -30,15 +49,11 @@ export class PageHeaderComponent<T extends IListable> {
|
||||
@Input() helpModeKey?: 'dossier' | 'document';
|
||||
@Input() searchPosition: SearchPosition = SearchPositions.afterFilters;
|
||||
@Output() readonly closeAction = new EventEmitter();
|
||||
|
||||
readonly filterService = inject(FilterService, { optional: true });
|
||||
readonly searchService = inject<SearchService<T>>(SearchService<T>, { optional: true });
|
||||
readonly filters$ = this.filterService?.filterGroups$.pipe(filterEach(f => !!f.icon));
|
||||
readonly showResetFilters$ = this.#showResetFilters$;
|
||||
|
||||
constructor(
|
||||
@Optional() readonly filterService: FilterService,
|
||||
@Optional() readonly searchService: SearchService<T>,
|
||||
) {}
|
||||
|
||||
get filterHelpModeKey() {
|
||||
return this.helpModeKey ? (this.helpModeKey === 'dossier' ? 'filter_dossier_list' : 'filter_documents') : '';
|
||||
}
|
||||
@ -48,15 +63,15 @@ export class PageHeaderComponent<T extends IListable> {
|
||||
return of(false);
|
||||
}
|
||||
|
||||
return combineLatest([this.filterService.showResetFilters$, this.searchService.valueChanges$]).pipe(
|
||||
return combineLatest([this.filterService.showResetFilters$, this.searchService?.valueChanges$ ?? of(undefined)]).pipe(
|
||||
map(([showResetFilters, searchValue]) => showResetFilters || !!searchValue),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
}
|
||||
|
||||
resetFilters(): void {
|
||||
this.filterService.reset();
|
||||
this.searchService.reset();
|
||||
this.filterService?.reset();
|
||||
this.searchService?.reset();
|
||||
}
|
||||
|
||||
trackByLabel<K extends { label?: string }>(_index: number, item: K): string | undefined {
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import { ChangeDetectionStrategy, Component, HostListener, Input, OnInit } from '@angular/core';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { delay, map, startWith } from 'rxjs/operators';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, HostListener, Input, OnInit } from '@angular/core';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { combineLatest, fromEvent, Observable } from 'rxjs';
|
||||
import { delay, map, startWith } from 'rxjs/operators';
|
||||
import { shareDistinctLast } from '../../utils';
|
||||
|
||||
const ButtonTypes = {
|
||||
@ -16,6 +18,8 @@ type ButtonType = keyof typeof ButtonTypes;
|
||||
templateUrl: './scroll-button.component.html',
|
||||
styleUrls: ['./scroll-button.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [AsyncPipe, MatIcon],
|
||||
})
|
||||
export class ScrollButtonComponent implements OnInit {
|
||||
readonly buttonType = ButtonTypes;
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import { filter, map, startWith, tap } from 'rxjs/operators';
|
||||
import { Id, IListable } from '../models';
|
||||
import { GenericService, QueryParam } from '../../services';
|
||||
import { getLength, List, mapEach, shareDistinctLast, shareLast } from '../../utils';
|
||||
import { GenericService, QueryParam } from '../../services/generic.service';
|
||||
import { getLength, mapEach, shareDistinctLast, shareLast } from '../../utils/operators';
|
||||
import { List } from '../../utils/types/iqser-types';
|
||||
import { IListable } from '../models/listable';
|
||||
import { Id } from '../models/trackable';
|
||||
|
||||
@Injectable()
|
||||
/**
|
||||
@ -14,14 +16,14 @@ export class EntitiesService<
|
||||
Class extends Interface & IListable<PrimaryKey>,
|
||||
PrimaryKey extends Id = Class['id'],
|
||||
> extends GenericService<Interface> {
|
||||
readonly noData$: Observable<boolean>;
|
||||
readonly all$: Observable<Class[]>;
|
||||
readonly allLength$: Observable<number>;
|
||||
protected readonly _defaultModelPath: string = '';
|
||||
protected readonly _entityClass?: new (entityInterface: Interface, ...args: unknown[]) => Class;
|
||||
protected readonly _entityChanged$ = new Subject<Class>();
|
||||
protected readonly _entityDeleted$ = new Subject<Class>();
|
||||
protected readonly _all$ = new BehaviorSubject<Class[]>([]);
|
||||
readonly noData$: Observable<boolean>;
|
||||
readonly all$: Observable<Class[]>;
|
||||
readonly allLength$: Observable<number>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
|
||||
import { map, switchMap, tap } from 'rxjs/operators';
|
||||
import { FilterService, getFilteredEntities } from '../../filtering';
|
||||
import { SearchService } from '../../search';
|
||||
import { SortingService } from '../../sorting';
|
||||
import { getLength, shareDistinctLast, shareLast, some } from '../../utils';
|
||||
import { Id, IListable } from '../models';
|
||||
import { getFilteredEntities } from '../../filtering/filter-utils';
|
||||
import { FilterService } from '../../filtering/filter.service';
|
||||
import { SearchService } from '../../search/search.service';
|
||||
import { SortingService } from '../../sorting/sorting.service';
|
||||
import { getLength, shareDistinctLast, shareLast, some } from '../../utils/operators';
|
||||
import { IListable } from '../models/listable';
|
||||
import { Id } from '../models/trackable';
|
||||
import { EntitiesService } from './entities.service';
|
||||
|
||||
@Injectable()
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Id, IListable } from '../models';
|
||||
import { EntitiesService } from './entities.service';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
import { mapEach } from '../../utils';
|
||||
import { PaginationSettings } from '../../pagination';
|
||||
import { PaginationSettings } from '../../pagination/pagination-settings';
|
||||
import { mapEach } from '../../utils/operators';
|
||||
import { IListable } from '../models/listable';
|
||||
import { Id } from '../models/trackable';
|
||||
import { EntitiesService } from './entities.service';
|
||||
|
||||
interface PaginatedResponse<Interface> {
|
||||
data: Interface[];
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
import { AsyncPipe, NgClass } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, Input, Optional } from '@angular/core';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { SortingOrders, SortingService } from '../../sorting';
|
||||
import { KeysOf } from '../../utils';
|
||||
import { Id, IListable } from '../models';
|
||||
@ -8,6 +12,8 @@ import { Id, IListable } from '../models';
|
||||
templateUrl: './table-column-name.component.html',
|
||||
styleUrls: ['./table-column-name.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [MatIcon, MatTooltip, TranslateModule, AsyncPipe, NgClass],
|
||||
})
|
||||
export class TableColumnNameComponent<T extends IListable<PrimaryKey>, PrimaryKey extends Id = T['id']> {
|
||||
readonly sortingOrders = SortingOrders;
|
||||
|
||||
@ -1,23 +1,44 @@
|
||||
/* eslint-disable @angular-eslint/prefer-on-push-component-change-detection */
|
||||
import { CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { AsyncPipe, NgClass } from '@angular/common';
|
||||
import { AfterViewInit, Component, forwardRef, HostListener, Inject, Input, OnDestroy, Optional, ViewChild } from '@angular/core';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { delay, tap } from 'rxjs/operators';
|
||||
import { AutoUnsubscribe, trackByFactory } from '../../utils';
|
||||
import { Id, IListable } from '../models';
|
||||
import { ListingComponent, ListingService } from '../index';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { HelpModeService } from '../../help-mode';
|
||||
import { HasScrollbarDirective } from '../../directives';
|
||||
import { delay, tap } from 'rxjs/operators';
|
||||
import { HasScrollbarDirective } from '../../directives/has-scrollbar.directive';
|
||||
import { HelpModeService } from '../../help-mode/help-mode.service';
|
||||
import { SnakeCasePipe } from '../../pipes/snake-case.pipe';
|
||||
import { AutoUnsubscribe } from '../../utils/auto-unsubscribe.directive';
|
||||
import { trackByFactory } from '../../utils/functions';
|
||||
import { ListingComponent } from '../listing-component.directive';
|
||||
import { IListable } from '../models/listable';
|
||||
import { Id } from '../models/trackable';
|
||||
import { ListingService } from '../services/listing.service';
|
||||
import { TableItemComponent } from './table-item/table-item.component';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-table-content',
|
||||
templateUrl: './table-content.component.html',
|
||||
styleUrls: ['./table-content.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
CdkVirtualScrollViewport,
|
||||
AsyncPipe,
|
||||
CdkFixedSizeVirtualScroll,
|
||||
HasScrollbarDirective,
|
||||
CdkVirtualForOf,
|
||||
SnakeCasePipe,
|
||||
NgClass,
|
||||
RouterLink,
|
||||
TableItemComponent,
|
||||
],
|
||||
})
|
||||
export class TableContentComponent<Class extends IListable<PrimaryKey>, PrimaryKey extends Id = Class['id']>
|
||||
extends AutoUnsubscribe
|
||||
implements OnDestroy, AfterViewInit
|
||||
{
|
||||
private _lastScrolledIndex = 0;
|
||||
private _multiSelectActive$ = new BehaviorSubject(false);
|
||||
@Input() itemSize!: number;
|
||||
@Input() itemMouseEnterFn?: (entity: Class) => void;
|
||||
@Input() itemMouseLeaveFn?: (entity: Class) => void;
|
||||
@ -26,13 +47,9 @@ export class TableContentComponent<Class extends IListable<PrimaryKey>, PrimaryK
|
||||
@Input() rowIdPrefix: string = 'item';
|
||||
@Input() namePropertyKey?: string;
|
||||
readonly trackBy = trackByFactory<Class>();
|
||||
|
||||
@ViewChild(CdkVirtualScrollViewport, { static: true }) readonly scrollViewport!: CdkVirtualScrollViewport;
|
||||
@ViewChild(HasScrollbarDirective, { static: true }) readonly hasScrollbarDirective!: HasScrollbarDirective;
|
||||
|
||||
private _lastScrolledIndex = 0;
|
||||
private _multiSelectActive$ = new BehaviorSubject(false);
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ListingComponent)) readonly listingComponent: ListingComponent<Class>,
|
||||
readonly listingService: ListingService<Class>,
|
||||
|
||||
@ -1,22 +1,25 @@
|
||||
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, forwardRef, Inject, Input, OnChanges } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { ListingComponent } from '../..';
|
||||
import { IListable } from '../../models';
|
||||
import { ListingService } from '../../services';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import { RoundCheckboxComponent } from '../../../inputs/round-checkbox/round-checkbox.component';
|
||||
import { ListingComponent } from '../../listing-component.directive';
|
||||
import { IListable } from '../../models/listable';
|
||||
import { ListingService } from '../../services/listing.service';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-table-item [entity]',
|
||||
templateUrl: './table-item.component.html',
|
||||
styleUrls: ['./table-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [RoundCheckboxComponent, AsyncPipe, NgTemplateOutlet],
|
||||
})
|
||||
export class TableItemComponent<T extends IListable> implements OnChanges {
|
||||
@Input() entity!: T;
|
||||
@Input() selectionEnabled = false;
|
||||
|
||||
readonly isSelected$: Observable<boolean>;
|
||||
readonly #entityChanged$ = new BehaviorSubject<T>(this.entity);
|
||||
@Input() selectionEnabled = false;
|
||||
readonly isSelected$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ListingComponent)) readonly listingComponent: ListingComponent<T>,
|
||||
|
||||
@ -1,13 +1,28 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, TemplateRef } from '@angular/core';
|
||||
import { FilterService } from '../../filtering';
|
||||
import { EntitiesService, ListingService } from '../services';
|
||||
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, inject, Input, TemplateRef } from '@angular/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { SyncWidthDirective } from '../../directives';
|
||||
import { FilterService, IqserFiltersModule } from '../../filtering';
|
||||
import { RoundCheckboxComponent } from '../../inputs';
|
||||
import { Id, IListable, ListingMode, ListingModes, TableColumnConfig } from '../models';
|
||||
import { EntitiesService, ListingService } from '../services';
|
||||
import { TableColumnNameComponent } from '../table-column-name/table-column-name.component';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-table-header [tableHeaderLabel]',
|
||||
templateUrl: './table-header.component.html',
|
||||
styleUrls: ['./table-header.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [
|
||||
RoundCheckboxComponent,
|
||||
AsyncPipe,
|
||||
TranslateModule,
|
||||
NgTemplateOutlet,
|
||||
IqserFiltersModule,
|
||||
SyncWidthDirective,
|
||||
TableColumnNameComponent,
|
||||
],
|
||||
})
|
||||
export class TableHeaderComponent<T extends IListable<PrimaryKey>, PrimaryKey extends Id = T['id']> {
|
||||
readonly listingModes = ListingModes;
|
||||
@ -21,11 +36,10 @@ export class TableHeaderComponent<T extends IListable<PrimaryKey>, PrimaryKey ex
|
||||
@Input() bulkActions?: TemplateRef<unknown>;
|
||||
@Input() helpModeKey?: string;
|
||||
|
||||
readonly quickFilters$ = this.filterService.getFilterModels$('quickFilters');
|
||||
readonly quickFilters$ = inject(FilterService).getFilterModels$('quickFilters');
|
||||
|
||||
constructor(
|
||||
readonly entitiesService: EntitiesService<T, T>,
|
||||
readonly listingService: ListingService<T>,
|
||||
readonly filterService: FilterService,
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
@ -13,10 +14,13 @@ import {
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
import { Id, IListable, ListingModes, TableColumnConfig } from '../models';
|
||||
import { EmptyStateComponent } from '../../empty-state';
|
||||
import { ListingComponent } from '../listing-component.directive';
|
||||
import { Id, IListable, ListingModes, TableColumnConfig } from '../models';
|
||||
import { ScrollButtonComponent } from '../scroll-button/scroll-button.component';
|
||||
import { EntitiesService } from '../services';
|
||||
import { TableContentComponent } from '../table-content/table-content.component';
|
||||
import { TableHeaderComponent } from '../table-header/table-header.component';
|
||||
|
||||
const SCROLLBAR_WIDTH = 11;
|
||||
|
||||
@ -24,10 +28,12 @@ const SCROLLBAR_WIDTH = 11;
|
||||
selector: 'iqser-table [tableColumnConfigs] [itemSize]',
|
||||
templateUrl: './table.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [TableHeaderComponent, NgTemplateOutlet, AsyncPipe, EmptyStateComponent, ScrollButtonComponent, TableContentComponent],
|
||||
})
|
||||
export class TableComponent<Class extends IListable<PrimaryKey>, PrimaryKey extends Id = Class['id']> implements OnChanges {
|
||||
@ViewChild(TableContentComponent, { static: true }) private readonly _tableContent!: TableContentComponent<Class>;
|
||||
readonly listingModes = ListingModes;
|
||||
|
||||
@Input() tableColumnConfigs!: readonly TableColumnConfig<Class>[];
|
||||
@Input() bulkActions?: TemplateRef<unknown>;
|
||||
@Input() headerTemplate?: TemplateRef<unknown>;
|
||||
@ -51,7 +57,6 @@ export class TableComponent<Class extends IListable<PrimaryKey>, PrimaryKey exte
|
||||
@Input() itemMouseEnterFn?: (entity: Class) => void;
|
||||
@Input() itemMouseLeaveFn?: (entity: Class) => void;
|
||||
@Output() readonly noDataAction = new EventEmitter<void>();
|
||||
@ViewChild(TableContentComponent, { static: true }) private readonly _tableContent!: TableContentComponent<Class>;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ListingComponent)) readonly listingComponent: ListingComponent<Class>,
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
@ -10,11 +11,13 @@ import {
|
||||
TemplateRef,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { filter, map, tap } from 'rxjs/operators';
|
||||
import { CircleButtonTypes } from '../../../buttons';
|
||||
import { CircleButtonComponent, CircleButtonTypes } from '../../../buttons';
|
||||
import { RoundCheckboxComponent } from '../../../inputs';
|
||||
import { ContextComponent, Debounce } from '../../../utils';
|
||||
import { IListable } from '../../models';
|
||||
import { Debounce, ContextComponent } from '../../../utils';
|
||||
import { ListingService } from '../../services';
|
||||
import { WorkflowColumn } from '../models/workflow-column.model';
|
||||
|
||||
@ -31,6 +34,8 @@ interface ColumnHeaderContext {
|
||||
templateUrl: './column-header.component.html',
|
||||
styleUrls: ['./column-header.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [AsyncPipe, TranslateModule, RoundCheckboxComponent, NgTemplateOutlet, CircleButtonComponent],
|
||||
})
|
||||
export class ColumnHeaderComponent<T extends IListable, K extends string> extends ContextComponent<ColumnHeaderContext> implements OnInit {
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
|
||||
@ -1,3 +1,13 @@
|
||||
import {
|
||||
CdkDrag,
|
||||
CdkDragDrop,
|
||||
CdkDragPlaceholder,
|
||||
CdkDragPreview,
|
||||
CdkDragStart,
|
||||
CdkDropList,
|
||||
CdkDropListGroup,
|
||||
} from '@angular/cdk/drag-drop';
|
||||
import { AsyncPipe, NgClass, NgTemplateOutlet } from '@angular/common';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
@ -14,16 +24,19 @@ import {
|
||||
TemplateRef,
|
||||
ViewChildren,
|
||||
} from '@angular/core';
|
||||
import { ListingComponent } from '../listing-component.directive';
|
||||
import { CdkDragDrop, CdkDragStart, CdkDropList } from '@angular/cdk/drag-drop';
|
||||
import { ContextComponent, Debounce, trackByFactory } from '../../utils';
|
||||
import { IListable } from '../models';
|
||||
import { EntitiesService, ListingService } from '../services';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { filter, tap } from 'rxjs/operators';
|
||||
import { WorkflowConfig } from './models/workflow-config.model';
|
||||
import { WorkflowColumn } from './models/workflow-column.model';
|
||||
import { EmptyStateComponent } from '../../empty-state';
|
||||
import { ContextComponent, Debounce, trackByFactory } from '../../utils';
|
||||
import { ListingComponent } from '../listing-component.directive';
|
||||
import { IListable } from '../models';
|
||||
import { EntitiesService, ListingService } from '../services';
|
||||
import { TableHeaderComponent } from '../table-header/table-header.component';
|
||||
import { ColumnHeaderComponent } from './column-header/column-header.component';
|
||||
import { EntityWrapper } from './models/entity-wrapper.model';
|
||||
import { WorkflowColumn } from './models/workflow-column.model';
|
||||
import { WorkflowConfig } from './models/workflow-config.model';
|
||||
|
||||
interface WorkflowContext<T> {
|
||||
noData: boolean;
|
||||
@ -37,8 +50,27 @@ interface WorkflowContext<T> {
|
||||
templateUrl: './workflow.component.html',
|
||||
styleUrls: ['./workflow.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [
|
||||
TableHeaderComponent,
|
||||
AsyncPipe,
|
||||
EmptyStateComponent,
|
||||
CdkDropListGroup,
|
||||
ColumnHeaderComponent,
|
||||
CdkDropList,
|
||||
CdkDrag,
|
||||
NgClass,
|
||||
CdkDragPlaceholder,
|
||||
NgTemplateOutlet,
|
||||
CdkDragPreview,
|
||||
MatIcon,
|
||||
],
|
||||
})
|
||||
export class WorkflowComponent<T extends IListable, K extends string> extends ContextComponent<WorkflowContext<T>> implements OnInit {
|
||||
@ViewChildren(CdkDropList) private readonly _dropLists!: QueryList<CdkDropList>;
|
||||
private readonly _observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
|
||||
this._updateItemSize(entries[0]);
|
||||
});
|
||||
@Input() config!: WorkflowConfig<T, K>;
|
||||
@Input() itemClasses!: Record<string, (e: T) => boolean>;
|
||||
@Input() addElementIcon!: string;
|
||||
@ -51,9 +83,7 @@ export class WorkflowComponent<T extends IListable, K extends string> extends Co
|
||||
@Input() bulkActions?: TemplateRef<unknown>;
|
||||
@Output() readonly noDataAction = new EventEmitter<void>();
|
||||
@Output() readonly addElement = new EventEmitter<void>();
|
||||
|
||||
@ContentChild('workflowItemTemplate') readonly itemTemplate!: TemplateRef<{ entity: T }>;
|
||||
|
||||
readonly trackBy = trackByFactory<T>();
|
||||
itemHeight?: number;
|
||||
itemWidth?: number;
|
||||
@ -62,10 +92,6 @@ export class WorkflowComponent<T extends IListable, K extends string> extends Co
|
||||
selectionColumn?: WorkflowColumn<T, K>;
|
||||
readonly draggingEntities$ = new BehaviorSubject<T[]>([]);
|
||||
all: { [key: string]: EntityWrapper<T> } = {};
|
||||
@ViewChildren(CdkDropList) private readonly _dropLists!: QueryList<CdkDropList>;
|
||||
private readonly _observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
|
||||
this._updateItemSize(entries[0]);
|
||||
});
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ListingComponent)) readonly listingComponent: ListingComponent<T>,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, CanMatch, Route, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
|
||||
import { firstValueFrom, from, of } from 'rxjs';
|
||||
import { first, mergeMap } from 'rxjs/operators';
|
||||
@ -7,22 +8,16 @@ import { first, mergeMap } from 'rxjs/operators';
|
||||
import {
|
||||
DEFAULT_REDIRECT_KEY,
|
||||
IqserActivatedRouteSnapshot,
|
||||
IqserPermissionsData,
|
||||
IqserRoute,
|
||||
NavigationCommandsFn,
|
||||
NavigationExtrasFn,
|
||||
RedirectTo,
|
||||
RedirectToFn,
|
||||
} from '../types';
|
||||
import { isArray, isFunction, isRedirectWithParameters, isString, transformPermission } from '../utils';
|
||||
import { IqserPermissionsService } from './permissions.service';
|
||||
import { IqserRolesService } from './roles.service';
|
||||
import { isArray, isFunction, isRedirectWithParameters, isString, transformPermission } from '../utils';
|
||||
import { List } from '../../utils';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
|
||||
export interface IqserPermissionsData {
|
||||
readonly allow: string | List;
|
||||
readonly redirectTo?: RedirectTo | RedirectToFn;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { BehaviorSubject, Observable, of } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { List } from '../../utils/types/iqser-types';
|
||||
import { IqserPermissions, PermissionValidationFn } from '../types';
|
||||
|
||||
import { isArray, isString, toArray } from '../utils';
|
||||
import { IqserPermissions, PermissionValidationFn } from '../types';
|
||||
import { List } from '../../utils';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class IqserPermissionsService {
|
||||
readonly permissions$: Observable<IqserPermissions>;
|
||||
readonly #permissions$ = new BehaviorSubject<IqserPermissions>({});
|
||||
readonly permissions$: Observable<IqserPermissions>;
|
||||
|
||||
constructor() {
|
||||
this.permissions$ = this.#permissions$.asObservable();
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { List } from '../../utils/types/iqser-types';
|
||||
import { IqserRoles, RoleValidationFn } from '../types';
|
||||
import { isArray, isBoolean, isString, toArray } from '../utils';
|
||||
import { List } from '../../utils';
|
||||
import { IqserPermissionsService } from './permissions.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class IqserRolesService {
|
||||
readonly roles$: Observable<IqserRoles>;
|
||||
readonly #roles$ = new BehaviorSubject<IqserRoles>({});
|
||||
readonly roles$: Observable<IqserRoles>;
|
||||
|
||||
constructor(private readonly _permissionsService: IqserPermissionsService) {
|
||||
this.roles$ = this.#roles$.asObservable();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ActivatedRouteSnapshot, NavigationExtras, Route, RouterStateSnapshot } from '@angular/router';
|
||||
import { List } from '../utils';
|
||||
import { List } from '../utils/types/iqser-types';
|
||||
|
||||
export type IqserPermissions = Record<string, PermissionValidationFn>;
|
||||
export type IqserRoles = Record<string, RoleValidationFn | List>;
|
||||
@ -9,6 +9,11 @@ export interface IqserPermissionsRouterData {
|
||||
redirectTo?: RedirectTo | RedirectToFn;
|
||||
}
|
||||
|
||||
export interface IqserPermissionsData {
|
||||
readonly allow: string | List;
|
||||
readonly redirectTo?: RedirectTo | RedirectToFn;
|
||||
}
|
||||
|
||||
export interface IqserRedirectToNavigationParameters {
|
||||
navigationCommands: any[] | NavigationCommandsFn;
|
||||
navigationExtras?: NavigationExtras | NavigationExtrasFn;
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { AllowFn, IqserPermissionsRouterData, IqserRedirectToNavigationParameters } from './types';
|
||||
import { ActivatedRouteSnapshot, Route, RouterStateSnapshot } from '@angular/router';
|
||||
import { IqserPermissionsData } from './services/permissions-guard.service';
|
||||
import { List } from '../utils';
|
||||
import { AllowFn, IqserPermissionsData, IqserPermissionsRouterData, IqserRedirectToNavigationParameters } from './types';
|
||||
|
||||
export function isFunction<T>(value: unknown): value is T {
|
||||
return typeof value === 'function';
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { Id, IListable } from '../listing';
|
||||
import { shareDistinctLast } from '../utils';
|
||||
import { IListable } from '../listing/models/listable';
|
||||
import { Id } from '../listing/models/trackable';
|
||||
import { shareDistinctLast } from '../utils/operators';
|
||||
|
||||
@Injectable()
|
||||
export class SearchService<T extends IListable<PrimaryKey>, PrimaryKey extends Id = T['id']> {
|
||||
skip = false;
|
||||
private readonly _query$ = new BehaviorSubject('');
|
||||
skip = false;
|
||||
readonly valueChanges$ = this._query$.asObservable().pipe(shareDistinctLast());
|
||||
|
||||
get searchValue(): string {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { UI_ROOT_PATH_FN } from '../utils/tokens';
|
||||
import { getConfig } from './iqser-config.service';
|
||||
import { UI_ROOT_PATH_FN } from '../utils';
|
||||
|
||||
@Injectable()
|
||||
export class ApiPathInterceptor implements HttpInterceptor {
|
||||
|
||||
@ -2,7 +2,7 @@ import { inject, Injectable, InjectionToken, Injector, runInInjectionContext } f
|
||||
import { ActivatedRouteSnapshot, CanActivate, CanActivateFn, GuardResult, RouterStateSnapshot, UrlTree } from '@angular/router';
|
||||
import { concatMap, firstValueFrom, from, last, Observable, of, takeWhile } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { LoadingService } from '../loading';
|
||||
import { LoadingService } from '../loading/loading.service';
|
||||
import { SkeletonService } from './skeleton.service';
|
||||
|
||||
@Injectable({
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import { filter, map, startWith } from 'rxjs/operators';
|
||||
import { Entity, Id } from '../listing';
|
||||
import { List, shareLast } from '../utils';
|
||||
import { isArray } from '../permissions';
|
||||
import { Entity } from '../listing/models/entity.model';
|
||||
import { Id } from '../listing/models/trackable';
|
||||
import { isArray } from '../permissions/utils';
|
||||
import { shareLast } from '../utils/operators';
|
||||
import { List } from '../utils/types/iqser-types';
|
||||
|
||||
@Injectable()
|
||||
export abstract class EntitiesMapService<Interface, Class extends Entity<Interface, PrimaryKey>, PrimaryKey extends Id = Class['id']> {
|
||||
protected readonly _map = new Map<Id, BehaviorSubject<Class[]>>();
|
||||
readonly #entityChanged$ = new Subject<Class>();
|
||||
readonly #entitiesChanged$ = new BehaviorSubject<boolean>(false);
|
||||
readonly #entityDeleted$ = new Subject<Class>();
|
||||
protected readonly _map = new Map<Id, BehaviorSubject<Class[]>>();
|
||||
|
||||
get empty(): boolean {
|
||||
return this._map.size === 0;
|
||||
|
||||
@ -1,18 +1,13 @@
|
||||
import { HttpClient, HttpEvent, HttpParams } from '@angular/common/http';
|
||||
import { inject } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { HeadersConfiguration, List } from '../utils';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { HeadersConfiguration } from '../utils/headers-configuration';
|
||||
import { List } from '../utils/types/iqser-types';
|
||||
|
||||
export const ROOT_CHANGES_KEY = 'root';
|
||||
export const LAST_CHECKED_OFFSET = 30000;
|
||||
|
||||
export interface HeaderOptions {
|
||||
readonly authorization?: boolean;
|
||||
readonly accept?: boolean;
|
||||
readonly contentType?: boolean;
|
||||
}
|
||||
|
||||
export interface QueryParam {
|
||||
readonly key: string;
|
||||
readonly value: string | number | boolean;
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { Inject, inject, Injectable } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { CacheApiService, wipeAllCaches } from '../caching';
|
||||
import { IqserAppConfig } from '../utils';
|
||||
import { CacheApiService } from '../caching/cache-api.service';
|
||||
import { wipeAllCaches } from '../caching/cache-utils';
|
||||
import { IqserAppConfig } from '../utils/iqser-app-config';
|
||||
|
||||
@Injectable()
|
||||
export class IqserConfigService<T extends IqserAppConfig = IqserAppConfig> {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { APP_BASE_HREF } from '@angular/common';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { List } from '../utils';
|
||||
import { List } from '../utils/types/iqser-types';
|
||||
import { GenericService } from './generic.service';
|
||||
import { APP_BASE_HREF } from '@angular/common';
|
||||
|
||||
export type UserAttributes = Record<string, List>;
|
||||
|
||||
@ -14,9 +14,9 @@ export const KEYS = {
|
||||
|
||||
@Injectable()
|
||||
export abstract class IqserUserPreferenceService extends GenericService<UserAttributes> {
|
||||
#userAttributes: UserAttributes = {};
|
||||
protected abstract readonly _devFeaturesEnabledKey: string;
|
||||
protected readonly _serviceName: string = 'tenant-user-management';
|
||||
#userAttributes: UserAttributes = {};
|
||||
|
||||
get userAttributes(): UserAttributes {
|
||||
return this.#userAttributes;
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable, switchMap } from 'rxjs';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { HeadersConfiguration, mapEach } from '../utils';
|
||||
import { HeadersConfiguration } from '../utils/headers-configuration';
|
||||
import { mapEach } from '../utils/operators';
|
||||
|
||||
@Injectable()
|
||||
export abstract class StatsService<E, I = E> {
|
||||
readonly #http = inject(HttpClient);
|
||||
readonly #map = new Map<string, BehaviorSubject<E>>();
|
||||
protected abstract readonly _primaryKey: string;
|
||||
protected abstract readonly _entityClass: new (entityInterface: I, ...args: unknown[]) => E;
|
||||
protected abstract readonly _defaultModelPath: string;
|
||||
protected readonly _serviceName: string = 'redaction-gateway-v1';
|
||||
|
||||
readonly #http = inject(HttpClient);
|
||||
readonly #map = new Map<string, BehaviorSubject<E>>();
|
||||
|
||||
getFor(ids: string[]): Observable<E[]> {
|
||||
const request = this.#http.post<I[]>(`/${this._serviceName}/${encodeURI(this._defaultModelPath)}`, ids, {
|
||||
headers: HeadersConfiguration.getHeaders(),
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { IListable } from '../listing/models/listable';
|
||||
import { Id } from '../listing/models/trackable';
|
||||
import { shareDistinctLast } from '../utils/operators';
|
||||
import { KeysOf } from '../utils/types/utility-types';
|
||||
import { sort } from './functions';
|
||||
import { SortingOption } from './models/sorting-option.model';
|
||||
import { SortingOrders } from './models/sorting-order.type';
|
||||
import { KeysOf, shareDistinctLast } from '../utils';
|
||||
import { Id, IListable } from '../listing';
|
||||
import { sort } from './functions';
|
||||
|
||||
@Injectable()
|
||||
export class SortingService<T extends IListable<PrimaryKey>, PrimaryKey extends Id = T['id']> {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
export * from './keycloak-initializer';
|
||||
export * from './services/keycloak-status.service';
|
||||
export * from './services';
|
||||
export * from './keycloak-initializer';
|
||||
export * from './tenants.module';
|
||||
export * from './tenant-select/tenant-select.component';
|
||||
export * from './services/keycloak-status.service';
|
||||
export * from './types';
|
||||
|
||||
@ -1,35 +1,11 @@
|
||||
import { IqserAppConfig, UI_ROOT } from '../utils';
|
||||
import { KeycloakOptions, KeycloakService } from 'keycloak-angular';
|
||||
import { KeycloakStatusService } from './services/keycloak-status.service';
|
||||
import { inject } from '@angular/core';
|
||||
import { getConfig } from '../services';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
export function getKeycloakOptions(baseUrl: string, config: IqserAppConfig, tenant: string): KeycloakOptions {
|
||||
let oauthUrl = config.OAUTH_URL;
|
||||
if (!oauthUrl.startsWith('http')) {
|
||||
oauthUrl = oauthUrl.startsWith('/') ? oauthUrl : '/' + oauthUrl;
|
||||
oauthUrl = window.location.origin + oauthUrl;
|
||||
}
|
||||
|
||||
return {
|
||||
config: {
|
||||
url: oauthUrl,
|
||||
realm: tenant,
|
||||
clientId: config.OAUTH_CLIENT_ID,
|
||||
},
|
||||
initOptions: {
|
||||
checkLoginIframe: false,
|
||||
onLoad: 'check-sso',
|
||||
silentCheckSsoRedirectUri: window.location.origin + baseUrl + '/assets/oauth/silent-refresh.html',
|
||||
flow: 'standard',
|
||||
enableLogging: true,
|
||||
},
|
||||
enableBearerInterceptor: true,
|
||||
loadUserProfileAtStartUp: true,
|
||||
};
|
||||
}
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { getConfig } from '../services/iqser-config.service';
|
||||
import { UI_ROOT } from '../utils/tokens';
|
||||
import { getKeycloakOptions } from './keycloak-options';
|
||||
import { KeycloakStatusService } from './services/keycloak-status.service';
|
||||
|
||||
function configureAutomaticRedirectToLoginScreen(keyCloakService: KeycloakService, keycloakStatusService: KeycloakStatusService) {
|
||||
const keycloakInstance = keyCloakService.getKeycloakInstance();
|
||||
|
||||
27
src/lib/tenants/keycloak-options.ts
Normal file
27
src/lib/tenants/keycloak-options.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { KeycloakOptions } from 'keycloak-angular';
|
||||
import { IqserAppConfig } from '../utils/iqser-app-config';
|
||||
|
||||
export function getKeycloakOptions(baseUrl: string, config: IqserAppConfig, tenant: string): KeycloakOptions {
|
||||
let oauthUrl = config.OAUTH_URL;
|
||||
if (!oauthUrl.startsWith('http')) {
|
||||
oauthUrl = oauthUrl.startsWith('/') ? oauthUrl : '/' + oauthUrl;
|
||||
oauthUrl = window.location.origin + oauthUrl;
|
||||
}
|
||||
|
||||
return {
|
||||
config: {
|
||||
url: oauthUrl,
|
||||
realm: tenant,
|
||||
clientId: config.OAUTH_CLIENT_ID,
|
||||
},
|
||||
initOptions: {
|
||||
checkLoginIframe: false,
|
||||
onLoad: 'check-sso',
|
||||
silentCheckSsoRedirectUri: window.location.origin + baseUrl + '/assets/oauth/silent-refresh.html',
|
||||
flow: 'standard',
|
||||
enableLogging: true,
|
||||
},
|
||||
enableBearerInterceptor: true,
|
||||
loadUserProfileAtStartUp: true,
|
||||
};
|
||||
}
|
||||
@ -1,9 +1,10 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { getConfig } from '../../services';
|
||||
import { getKeycloakOptions, TenantsService } from '../index';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { UI_ROOT } from '../../utils';
|
||||
import { getConfig } from '../../services/iqser-config.service';
|
||||
import { UI_ROOT } from '../../utils/tokens';
|
||||
import { getKeycloakOptions } from '../keycloak-options';
|
||||
import { TenantsService } from './tenants.service';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class KeycloakStatusService {
|
||||
|
||||
@ -5,11 +5,11 @@ import { KeycloakService } from 'keycloak-angular';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { LoadingService } from '../../loading';
|
||||
import { getConfig } from '../../services';
|
||||
import { getKeycloakOptions } from '../keycloak-initializer';
|
||||
import { selectTenantTranslations } from '../../translations/select-tenant-translations';
|
||||
import { UI_ROOT } from '../../utils';
|
||||
import { getKeycloakOptions } from '../keycloak-options';
|
||||
import { IStoredTenantId, TenantsService } from '../services';
|
||||
import { KeycloakStatusService } from '../services/keycloak-status.service';
|
||||
import { UI_ROOT } from '../../utils';
|
||||
import { selectTenantTranslations } from '../../translations/select-tenant-translations';
|
||||
|
||||
@Component({
|
||||
templateUrl: './tenant-select.component.html',
|
||||
@ -17,8 +17,7 @@ import { selectTenantTranslations } from '../../translations/select-tenant-trans
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TenantSelectComponent {
|
||||
@Input() isLoggedOut = false;
|
||||
@Input() noRoleLogOut = false;
|
||||
readonly #uiRoot = inject(UI_ROOT);
|
||||
protected readonly logger = inject(NGXLogger);
|
||||
protected readonly tenantsService = inject(TenantsService);
|
||||
protected storedTenants: IStoredTenantId[] = [];
|
||||
@ -32,7 +31,8 @@ export class TenantSelectComponent {
|
||||
tenantId: ['', Validators.required],
|
||||
});
|
||||
protected readonly translations = selectTenantTranslations;
|
||||
readonly #uiRoot = inject(UI_ROOT);
|
||||
@Input() isLoggedOut = false;
|
||||
@Input() noRoleLogOut = false;
|
||||
|
||||
constructor() {
|
||||
this.#loadStoredTenants();
|
||||
|
||||
@ -10,11 +10,13 @@ import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CircleButtonComponent, IconButtonComponent } from '../buttons';
|
||||
import { StopPropagationDirective } from '../directives';
|
||||
import { LogoComponent } from '../shared';
|
||||
import { CircleButtonComponent } from '../buttons/circle-button/circle-button.component';
|
||||
import { IconButtonComponent } from '../buttons/icon-button/icon-button.component';
|
||||
import { StopPropagationDirective } from '../directives/stop-propagation.directive';
|
||||
import { LogoComponent } from '../shared/logo/logo.component';
|
||||
import { SpacerComponent } from '../shared/spacer/spacer.component';
|
||||
import { TenantIdInterceptor, TenantIdResponseInterceptor } from './services';
|
||||
import { TenantIdInterceptor } from './services/tenant-id-interceptor';
|
||||
import { TenantIdResponseInterceptor } from './services/tenant-id-response-interceptor';
|
||||
import { TenantSelectComponent } from './tenant-select/tenant-select.component';
|
||||
|
||||
@NgModule({
|
||||
|
||||
@ -3,7 +3,8 @@ import { Subscription } from 'rxjs';
|
||||
import { OnDetach } from './custom-route-reuse.strategy';
|
||||
|
||||
/**
|
||||
* Inherit this class when you need to subscribe to observables in your components
|
||||
* @deprecated Use takeUntilDestroyed()
|
||||
* TODO: remove this asap
|
||||
*/
|
||||
@Directive()
|
||||
export abstract class AutoUnsubscribe implements OnDestroy, OnDetach {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
|
||||
import { Debounce } from '../utils';
|
||||
import { ComponentRef, Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Debounce } from './decorators/debounce.decorator';
|
||||
|
||||
export interface OnAttach {
|
||||
ngOnAttach(previousRoute?: ActivatedRouteSnapshot): void;
|
||||
@ -25,9 +25,9 @@ interface RouteStorageObject {
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CustomRouteReuseStrategy implements RouteReuseStrategy {
|
||||
readonly #storedRoutes = new Map<string, RouteStorageObject>();
|
||||
readonly attached$ = new Subject<ActivatedRouteSnapshot>();
|
||||
readonly detached$ = new Subject<ActivatedRouteSnapshot>();
|
||||
readonly #storedRoutes = new Map<string, RouteStorageObject>();
|
||||
|
||||
private static _removeTooltips(): void {
|
||||
while (document.getElementsByTagName('mat-tooltip-component').length > 0) {
|
||||
|
||||
@ -3,7 +3,7 @@ import { UntypedFormGroup } from '@angular/forms';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import dayjs, { type Dayjs } from 'dayjs';
|
||||
import { forOwn, has, isEqual, isPlainObject, transform } from 'lodash-es';
|
||||
import type { Id, ITrackable } from '../listing';
|
||||
import { Id, ITrackable } from '../listing/models/trackable';
|
||||
|
||||
export function capitalize(value: string | string): string {
|
||||
if (!value) {
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
import { HttpHeaders } from '@angular/common/http';
|
||||
import { HeaderOptions } from '../services/generic.service';
|
||||
|
||||
export interface HeaderOptions {
|
||||
readonly authorization?: boolean;
|
||||
readonly accept?: boolean;
|
||||
readonly contentType?: boolean;
|
||||
}
|
||||
|
||||
export class HeadersConfiguration {
|
||||
static getHeaders(options?: HeaderOptions): HttpHeaders {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { IqserConfigService, IqserUserPreferenceService } from '../../services';
|
||||
import { Type } from '@angular/core';
|
||||
import { IqserConfigService } from '../../services/iqser-config.service';
|
||||
import { IqserUserPreferenceService } from '../../services/iqser-user-preference.service';
|
||||
import { IqserAppConfig } from '../iqser-app-config';
|
||||
|
||||
export interface CommonUiOptions<
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user