ngx-edu-sharing-metaqs2 0.9.37 → 0.9.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Injectable, Optional, Inject, NgModule, SkipSelf, Pipe, Component, Input, Output, inject, Renderer2, Injector, ChangeDetectionStrategy, HostBinding, LOCALE_ID, ElementRef, ViewChild, Directive, signal, computed, ViewChildren, HostListener, EventEmitter, effect, enableProdMode, importProvidersFrom } from '@angular/core';
2
+ import { InjectionToken, Injectable, Optional, Inject, NgModule, SkipSelf, Pipe, Component, Input, Output, inject, Renderer2, Injector, ChangeDetectionStrategy, HostBinding, LOCALE_ID, ElementRef, ViewChild, Directive, DestroyRef, signal, computed, ViewChildren, HostListener, EventEmitter, effect, enableProdMode, importProvidersFrom } from '@angular/core';
3
3
  import * as i3$1 from '@angular/material/card';
4
4
  import { MatCard, MatCardHeader, MatCardTitle, MatCardContent, MatCardModule } from '@angular/material/card';
5
5
  import { MatTreeModule } from '@angular/material/tree';
@@ -13,7 +13,7 @@ import * as i6 from '@angular/material/button';
13
13
  import { MatButton, MatIconButton, MatButtonModule } from '@angular/material/button';
14
14
  import * as i2$2 from '@angular/material/progress-spinner';
15
15
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
16
- import * as i4 from '@angular/material/table';
16
+ import * as i5$1 from '@angular/material/table';
17
17
  import { MatTable, MatCell, MatColumnDef, MatHeaderCell, MatHeaderRow, MatRow, MatHeaderRowDef, MatRowDef, MatHeaderCellDef, MatCellDef, MatTableModule } from '@angular/material/table';
18
18
  import { MatGridListModule } from '@angular/material/grid-list';
19
19
  import * as i1$1 from '@angular/material/form-field';
@@ -21,14 +21,14 @@ import { MatFormFieldModule, MatFormField, MatLabel, MatSuffix } from '@angular/
21
21
  import { MatInput, MatInputModule } from '@angular/material/input';
22
22
  import { MatSidenavModule } from '@angular/material/sidenav';
23
23
  import * as i1$2 from '@angular/forms';
24
- import { FormControl, ReactiveFormsModule, FormsModule, FormGroup, FormRecord } from '@angular/forms';
24
+ import { FormControl, ReactiveFormsModule, FormsModule, FormRecord, FormGroup } from '@angular/forms';
25
25
  import * as i2 from '@angular/material/select';
26
26
  import { MatSelectModule } from '@angular/material/select';
27
27
  import { MatTooltip, MatTooltipModule } from '@angular/material/tooltip';
28
28
  import * as i1 from '@angular/common/http';
29
29
  import { HttpHeaders, HttpContext, HttpParams, provideHttpClient, withInterceptorsFromDi, HttpClient } from '@angular/common/http';
30
- import { pipe, of, BehaviorSubject, forkJoin, Subject, zip } from 'rxjs';
31
- import { map, catchError, startWith, take, filter, tap, finalize, takeUntil, shareReplay, distinctUntilChanged, switchMap, skipWhile } from 'rxjs/operators';
30
+ import { pipe, of, BehaviorSubject, Subject, combineLatest, forkJoin } from 'rxjs';
31
+ import { map, catchError, startWith, take, tap, switchMap, finalize, filter, throttleTime, takeUntil, shareReplay, distinctUntilChanged, skipWhile } from 'rxjs/operators';
32
32
  import * as i2$4 from '@angular/platform-browser';
33
33
  import { BrowserModule, createApplication } from '@angular/platform-browser';
34
34
  import { MatListModule } from '@angular/material/list';
@@ -40,7 +40,7 @@ import * as i3 from '@angular/material/core';
40
40
  import { DateAdapter, MAT_DATE_LOCALE, MAT_DATE_FORMATS, MatRipple } from '@angular/material/core';
41
41
  import * as i2$3 from '@ngx-translate/core';
42
42
  import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
43
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
43
+ import { toSignal, takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
44
44
  import { DateTime } from 'luxon';
45
45
  import * as i1$3 from '@angular/cdk/overlay';
46
46
  import { Overlay, OverlayRef } from '@angular/cdk/overlay';
@@ -1547,6 +1547,239 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
1547
1547
  type: Output
1548
1548
  }] } });
1549
1549
 
1550
+ /**
1551
+ * This class is a thin wrapper around the API services.
1552
+ */
1553
+ class MetaApiService {
1554
+ constructor(collectionsAPI, replicationsAPI, filterAPI, editorsAPI) {
1555
+ this.collectionsAPI = collectionsAPI;
1556
+ this.replicationsAPI = replicationsAPI;
1557
+ this.filterAPI = filterAPI;
1558
+ this.editorsAPI = editorsAPI;
1559
+ }
1560
+ /**
1561
+ * Get the filters for the quality matrix.
1562
+ * It pipes the observable to take only one value.
1563
+ */
1564
+ getSearchFilters() {
1565
+ return this.filterAPI.getQualitxMatrixFilters().pipe(take(1));
1566
+ }
1567
+ getCategoryFilters() {
1568
+ return this.getSearchFilters().pipe(map((filters) => filters.filter((filter) => filter.field !== 'timerange')));
1569
+ }
1570
+ getCollectionsFilter() {
1571
+ return this.collectionsAPI.getTopLevelCollection();
1572
+ }
1573
+ /**
1574
+ * Get the timerange filter for the quality matrix.
1575
+ * Returns the first filter of the historical timerange filters.
1576
+ */
1577
+ getTimerangeFilter() {
1578
+ return this.filterAPI.getHistoricalTimerange().pipe(take(1), map((filters) => filters[0]));
1579
+ }
1580
+ getMaterialCountMatrixPerCollection(nodeRef, oerOnly) {
1581
+ return this.collectionsAPI.getMaterialCountMatrixPerCollection(nodeRef, oerOnly);
1582
+ }
1583
+ getCollectionCompleteness(colId) {
1584
+ return this.collectionsAPI.getCompleteness(colId);
1585
+ }
1586
+ getQualityMatrixWithFiltersV2(body) {
1587
+ return this.replicationsAPI.getQualityMatrixV2(body);
1588
+ }
1589
+ getEditorialMaterialCounts(body) {
1590
+ return this.editorsAPI.getMaterialCount(body);
1591
+ }
1592
+ getMaterialTypeCountsByReplicationSource(body) {
1593
+ return this.replicationsAPI.getMaterialCountMatrixByReplicationSourceAndType(body);
1594
+ }
1595
+ getLicenseCountsByReplicationSource(body) {
1596
+ return this.replicationsAPI.getMaterialCountMatrixByReplicationSourceAndLicense(body);
1597
+ }
1598
+ getLicenseCountsByLicenseGroup(colId, filters) {
1599
+ return this.collectionsAPI.getMaterialCountMatrixByLicenseGroup1(colId, filters);
1600
+ }
1601
+ getMaterialCountMatrixByLicenseGroup(body) {
1602
+ return this.editorsAPI.getMaterialCountMatrixByLicenseGroup(body);
1603
+ }
1604
+ getCompletenessForDisciplinaryPortals(body) {
1605
+ return this.editorsAPI.getCompletenessForDisciplinaryPortals(body);
1606
+ }
1607
+ getCompletenessForReplicationSources(body) {
1608
+ return this.replicationsAPI.getCompletenessForReplicationSources(body);
1609
+ }
1610
+ getMaterialTypesMapping() {
1611
+ return this.filterAPI.getMaterialTypesMapping();
1612
+ }
1613
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MetaApiService, deps: [{ token: CollectionAPIService }, { token: ReplicationSourceAPIService }, { token: FilterAPIService }, { token: EditorsAPIService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1614
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MetaApiService, providedIn: 'root' }); }
1615
+ }
1616
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MetaApiService, decorators: [{
1617
+ type: Injectable,
1618
+ args: [{
1619
+ providedIn: 'root',
1620
+ }]
1621
+ }], ctorParameters: () => [{ type: CollectionAPIService }, { type: ReplicationSourceAPIService }, { type: FilterAPIService }, { type: EditorsAPIService }] });
1622
+
1623
+ /**
1624
+ * This service provides methods to create links to the editorial desk with specific filters.
1625
+ */
1626
+ /* This map makes it easier for me to keep track which issues are mapped to which filters */
1627
+ const FilterNames2Issues = {
1628
+ //Lizenzen
1629
+ 'virtual:editorial_license': ['oer', 'other_cc', 'copyright', 'without_license'],
1630
+ //Materialtypen werden im Constructor gesetzt
1631
+ 'virtual:oeh_lrt': [],
1632
+ 'virtual:editorial_exclusion': [
1633
+ 'outdated',
1634
+ 'without_preview',
1635
+ 'without_title',
1636
+ 'without_description',
1637
+ 'without_url',
1638
+ 'without_type',
1639
+ 'without_taxonomy_id',
1640
+ 'without_education_level',
1641
+ 'without_target_group',
1642
+ 'without_license',
1643
+ 'without_publisher',
1644
+ ],
1645
+ };
1646
+ // Here we map back the issues to the filter names in the editorial desk, so we can look up the filter name for a given issue
1647
+ const Issues2FilterNames = Object.entries(FilterNames2Issues).reduce((map, [key, value]) => {
1648
+ value.forEach((issue) => map.set(issue, key));
1649
+ return map;
1650
+ }, new Map());
1651
+ // maps our values to the values of the filter in the editorial desk
1652
+ const MapValuesForFilter = {
1653
+ 'virtual:editorial_exclusion': {
1654
+ outdated: null,
1655
+ without_preview: null,
1656
+ without_title: ['missing_title'],
1657
+ without_description: ['missing_description'],
1658
+ without_url: ['links'],
1659
+ without_type: ['missing_oeh_lrt'],
1660
+ without_taxonomy_id: ['without_taxonomy_id'],
1661
+ without_education_level: ['missing_educationalcontext'],
1662
+ without_target_group: ['missing_educationalintendedenduserrole'],
1663
+ without_license: ['missing_license'],
1664
+ without_publisher: ['missing_replicationsource'],
1665
+ },
1666
+ 'virtual:editorial_license': {
1667
+ oer: ['oer'],
1668
+ copyright: ['none_oer'],
1669
+ without_license: ['none'],
1670
+ },
1671
+ 'virtual:oeh_lrt': {},
1672
+ };
1673
+ /*
1674
+ This is a map from properties of a document to filter names
1675
+ */
1676
+ const PROPERTIES2FILTERS = new Map([
1677
+ ['metadata.educationalContexts', 'ccm:educationalcontext'],
1678
+ ['metadata.disciplines', 'virtual:taxonid'],
1679
+ //["responsibility", "virtual:collection_id_primary"] // das zeigt auf "sammlungszugehörigkeit" und ist falsch
1680
+ ]);
1681
+ class EditorialLinkService {
1682
+ constructor() {
1683
+ this.env = inject(ConfigHelperService);
1684
+ this.api = inject(MetaApiService);
1685
+ this.typesLoaded$ = new BehaviorSubject(false);
1686
+ this.api
1687
+ .getMaterialTypesMapping()
1688
+ .pipe(take(1))
1689
+ .subscribe((types) => {
1690
+ for (const [key, value] of Object.entries(types)) {
1691
+ Issues2FilterNames.set(key, 'virtual:oeh_lrt');
1692
+ MapValuesForFilter['virtual:oeh_lrt'][key] = value;
1693
+ }
1694
+ this.typesLoaded$.next(true);
1695
+ });
1696
+ }
1697
+ openByReplicationsourceAndIssueTypeWithFilters(source, issue, selectedFilters) {
1698
+ const filters = {};
1699
+ filters['virtual:audit_filter'] = ['all'];
1700
+ filters['ccm:oeh_publisher_combined'] = [source];
1701
+ filters['virtual:editorial_exclusion'] = MapValuesForFilter['virtual:editorial_exclusion'][issue];
1702
+ for (const [field, values] of Object.entries(selectedFilters)) {
1703
+ if (values && values.length) {
1704
+ const editorialFiltername = PROPERTIES2FILTERS.get(field);
1705
+ filters[editorialFiltername] = values;
1706
+ }
1707
+ }
1708
+ const theUrl = this.env.eduSharingPath + '/components/editorial-desk';
1709
+ const params = new URLSearchParams();
1710
+ params.set('mode', 'audit');
1711
+ params.set('filters', JSON.stringify(filters));
1712
+ window.open(`${theUrl}?${params}`, 'editor_frontend');
1713
+ }
1714
+ openByCollectionAndIssueType(collectionId, issueType, pageTitle) {
1715
+ const filters = {};
1716
+ filters['virtual:audit_filter'] = ['all'];
1717
+ filters['virtual:editorial_exclusion'] = MapValuesForFilter['virtual:editorial_exclusion'][issueType];
1718
+ filters['virtual:collection_id_primary'] = [collectionId];
1719
+ const theUrl = this.env.eduSharingPath + '/components/editorial-desk';
1720
+ const params = new URLSearchParams();
1721
+ params.set('title', pageTitle);
1722
+ params.set('mode', 'audit');
1723
+ params.set('filters', JSON.stringify(filters));
1724
+ window.open(`${theUrl}?${params}`, 'editor_frontend');
1725
+ }
1726
+ openByCollectionId(collectionId) {
1727
+ const theUrl = this.env.eduSharingPath + '/components/editorial-desk';
1728
+ const params = new URLSearchParams();
1729
+ params.set('ids', collectionId);
1730
+ params.set('mode', 'render');
1731
+ window.open(`${theUrl}?${params}`, 'editor_frontend');
1732
+ }
1733
+ /**
1734
+ * This method creates a link to the editorial desk with specific filters.
1735
+ * It returns the URL to the editorial desk with the filters applied or null if the issueId is not mapped to a filter.
1736
+ * With this we can render a link with an href attribute to the editorial desk in the frontend.
1737
+ * @see the counts-with-history.component.scss how we style links only if their hrefs are not null
1738
+ *
1739
+ * @param sourceType The type of the source, e.g. "replicationSource" or "collection"
1740
+ * @param sourceId The id of the source. This is the first column in the table.
1741
+ * @param issueId The id of the issue. These are the other columns in the table.
1742
+ */
1743
+ createLinkForCountsWithHistory(sourceType, sourceId, issueId) {
1744
+ const filters = {};
1745
+ filters['virtual:audit_filter'] = ['all'];
1746
+ // determine the "main" filter
1747
+ if (sourceType === 'replicationSource') {
1748
+ filters['ccm:oeh_publisher_combined'] = [sourceId];
1749
+ }
1750
+ else if (sourceType === 'collection') {
1751
+ filters['virtual:collection_id_primary'] = [sourceId];
1752
+ }
1753
+ if (!Issues2FilterNames.has(issueId)) {
1754
+ return null;
1755
+ }
1756
+ const filterName = Issues2FilterNames.get(issueId);
1757
+ if (!filterName) {
1758
+ // console.debug("No filter name found for issue id: " + issueId);
1759
+ return null;
1760
+ }
1761
+ const filterValue = MapValuesForFilter[filterName][issueId];
1762
+ if (!filterValue) {
1763
+ // console.debug("No filter value found for issue id: " + issueId);
1764
+ return null;
1765
+ }
1766
+ filters[filterName] = filterValue;
1767
+ const theUrl = this.env.eduSharingPath + '/components/editorial-desk';
1768
+ const params = new URLSearchParams();
1769
+ params.set('mode', 'audit');
1770
+ params.set('filters', JSON.stringify(filters));
1771
+ return `${theUrl}?${params}`;
1772
+ }
1773
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorialLinkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1774
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorialLinkService, providedIn: 'root' }); }
1775
+ }
1776
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorialLinkService, decorators: [{
1777
+ type: Injectable,
1778
+ args: [{
1779
+ providedIn: 'root',
1780
+ }]
1781
+ }], ctorParameters: () => [] });
1782
+
1550
1783
  const TOOLTIP_DATA = new InjectionToken('TOOLTIP_DATA');
1551
1784
  const TOOLTIP_REF = new InjectionToken('TOOLTIP_REF');
1552
1785
  const noop = Object.freeze(() => { });
@@ -2043,297 +2276,65 @@ class ProgressSpinnerComponent {
2043
2276
  see https://stackoverflow.com/questions/63579801/how-do-i-create-a-custom-overlay-container-for-angular-material
2044
2277
  how to create a overlay container.
2045
2278
  With such a directive we can have a spinner that greys-out only e.g. the table like seen here:
2046
- https://reppners.github.io/ngx-cdk-dynamic-overlay-container/
2047
- */
2048
- this.progressSpinnerOverlayConfig['positionStrategy'] = this.overlayService.positionFlexibleConnected(this.el);
2049
- }
2050
- // Create Overlay for progress spinner
2051
- this.overlayRef = this.overlayService.createOverlay(this.progressSpinnerOverlayConfig);
2052
- }
2053
- ngOnChanges(changes) {
2054
- changes.displayProgressSpinner.currentValue
2055
- ? this.overlayService.attachTemplatePortal(this.overlayRef, this.progressSpinnerRef, this.vcRef)
2056
- : this.overlayRef.detach();
2057
- }
2058
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProgressSpinnerComponent, deps: [{ token: i0.ViewContainerRef }, { token: OverlayService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
2059
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ProgressSpinnerComponent, isStandalone: true, selector: "metaqs2-progress-spinner", inputs: { color: "color", diameter: "diameter", strokeWidth: "strokeWidth", backdropEnabled: "backdropEnabled", positionGloballyCenter: "positionGloballyCenter", displayProgressSpinner: "displayProgressSpinner" }, viewQueries: [{ propertyName: "progressSpinnerRef", first: true, predicate: ["progressSpinnerRef"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<ng-template #progressSpinnerRef>\n <mat-spinner [color]=\"color\" [diameter]=\"diameter\" [strokeWidth]=\"strokeWidth\">\n\t</mat-spinner>\n</ng-template>", styles: [""], dependencies: [{ kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i2$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] }); }
2060
- }
2061
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProgressSpinnerComponent, decorators: [{
2062
- type: Component,
2063
- args: [{ selector: 'metaqs2-progress-spinner', standalone: true, imports: [MatProgressSpinnerModule], template: "<ng-template #progressSpinnerRef>\n <mat-spinner [color]=\"color\" [diameter]=\"diameter\" [strokeWidth]=\"strokeWidth\">\n\t</mat-spinner>\n</ng-template>" }]
2064
- }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: OverlayService }, { type: i0.ElementRef }], propDecorators: { color: [{
2065
- type: Input
2066
- }], diameter: [{
2067
- type: Input
2068
- }], strokeWidth: [{
2069
- type: Input
2070
- }], backdropEnabled: [{
2071
- type: Input
2072
- }], positionGloballyCenter: [{
2073
- type: Input
2074
- }], displayProgressSpinner: [{
2075
- type: Input
2076
- }], progressSpinnerRef: [{
2077
- type: ViewChild,
2078
- args: ['progressSpinnerRef', { static: true }]
2079
- }] } });
2080
-
2081
- class ScrollMarkerDirective {
2082
- constructor() {
2083
- this.element = inject(ElementRef);
2084
- }
2085
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ScrollMarkerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2086
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: ScrollMarkerDirective, isStandalone: true, selector: "[metaqs2ScrollMarker]", ngImport: i0 }); }
2087
- }
2088
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ScrollMarkerDirective, decorators: [{
2089
- type: Directive,
2090
- args: [{
2091
- selector: '[metaqs2ScrollMarker]',
2092
- standalone: true,
2093
- }]
2094
- }] });
2095
-
2096
- /**
2097
- * This class is a thin wrapper around the API services.
2098
- */
2099
- class MetaApiService {
2100
- constructor(collectionsAPI, replicationsAPI, filterAPI, editorsAPI) {
2101
- this.collectionsAPI = collectionsAPI;
2102
- this.replicationsAPI = replicationsAPI;
2103
- this.filterAPI = filterAPI;
2104
- this.editorsAPI = editorsAPI;
2105
- }
2106
- /**
2107
- * Get the filters for the quality matrix.
2108
- * It pipes the observable to take only one value.
2109
- */
2110
- getSearchFilters() {
2111
- return this.filterAPI.getQualitxMatrixFilters().pipe(take(1));
2112
- }
2113
- getCategoryFilters() {
2114
- return this.getSearchFilters().pipe(map((filters) => filters.filter((filter) => filter.field !== 'timerange')));
2115
- }
2116
- getCollectionsFilter() {
2117
- return this.collectionsAPI.getTopLevelCollection();
2118
- }
2119
- /**
2120
- * Get the timerange filter for the quality matrix.
2121
- * Returns the first filter of the historical timerange filters.
2122
- */
2123
- getTimerangeFilter() {
2124
- return this.filterAPI.getHistoricalTimerange().pipe(take(1), map((filters) => filters[0]));
2125
- }
2126
- getMaterialCountMatrixPerCollection(nodeRef, oerOnly) {
2127
- return this.collectionsAPI.getMaterialCountMatrixPerCollection(nodeRef, oerOnly);
2128
- }
2129
- getCollectionCompleteness(colId) {
2130
- return this.collectionsAPI.getCompleteness(colId);
2131
- }
2132
- getQualityMatrixWithFiltersV2(body) {
2133
- return this.replicationsAPI.getQualityMatrixV2(body);
2134
- }
2135
- getEditorialMaterialCounts(body) {
2136
- return this.editorsAPI.getMaterialCount(body);
2137
- }
2138
- getMaterialTypeCountsByReplicationSource(body) {
2139
- return this.replicationsAPI.getMaterialCountMatrixByReplicationSourceAndType(body);
2140
- }
2141
- getLicenseCountsByReplicationSource(body) {
2142
- return this.replicationsAPI.getMaterialCountMatrixByReplicationSourceAndLicense(body);
2143
- }
2144
- getLicenseCountsByLicenseGroup(colId, filters) {
2145
- return this.collectionsAPI.getMaterialCountMatrixByLicenseGroup1(colId, filters);
2146
- }
2147
- getMaterialCountMatrixByLicenseGroup(body) {
2148
- return this.editorsAPI.getMaterialCountMatrixByLicenseGroup(body);
2149
- }
2150
- getCompletenessForDisciplinaryPortals(body) {
2151
- return this.editorsAPI.getCompletenessForDisciplinaryPortals(body);
2152
- }
2153
- getCompletenessForReplicationSources(body) {
2154
- return this.replicationsAPI.getCompletenessForReplicationSources(body);
2155
- }
2156
- getMaterialTypesMapping() {
2157
- return this.filterAPI.getMaterialTypesMapping();
2158
- }
2159
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MetaApiService, deps: [{ token: CollectionAPIService }, { token: ReplicationSourceAPIService }, { token: FilterAPIService }, { token: EditorsAPIService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2160
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MetaApiService, providedIn: 'root' }); }
2161
- }
2162
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MetaApiService, decorators: [{
2163
- type: Injectable,
2164
- args: [{
2165
- providedIn: 'root',
2166
- }]
2167
- }], ctorParameters: () => [{ type: CollectionAPIService }, { type: ReplicationSourceAPIService }, { type: FilterAPIService }, { type: EditorsAPIService }] });
2168
-
2169
- /**
2170
- * This service provides methods to create links to the editorial desk with specific filters.
2171
- */
2172
- /* This map makes it easier for me to keep track which issues are mapped to which filters */
2173
- const FilterNames2Issues = {
2174
- //Lizenzen
2175
- 'virtual:editorial_license': ['oer', 'other_cc', 'copyright', 'without_license'],
2176
- //Materialtypen werden im Constructor gesetzt
2177
- 'virtual:oeh_lrt': [],
2178
- 'virtual:editorial_exclusion': [
2179
- 'outdated',
2180
- 'without_preview',
2181
- 'without_title',
2182
- 'without_description',
2183
- 'without_url',
2184
- 'without_type',
2185
- 'without_taxonomy_id',
2186
- 'without_education_level',
2187
- 'without_target_group',
2188
- 'without_license',
2189
- 'without_publisher',
2190
- ],
2191
- };
2192
- // Here we map back the issues to the filter names in the editorial desk, so we can look up the filter name for a given issue
2193
- const Issues2FilterNames = Object.entries(FilterNames2Issues).reduce((map, [key, value]) => {
2194
- value.forEach((issue) => map.set(issue, key));
2195
- return map;
2196
- }, new Map());
2197
- // maps our values to the values of the filter in the editorial desk
2198
- const MapValuesForFilter = {
2199
- 'virtual:editorial_exclusion': {
2200
- outdated: null,
2201
- without_preview: null,
2202
- without_title: ['missing_title'],
2203
- without_description: ['missing_description'],
2204
- without_url: ['links'],
2205
- without_type: ['missing_oeh_lrt'],
2206
- without_taxonomy_id: ['without_taxonomy_id'],
2207
- without_education_level: ['missing_educationalcontext'],
2208
- without_target_group: ['missing_educationalintendedenduserrole'],
2209
- without_license: ['missing_license'],
2210
- without_publisher: ['missing_replicationsource'],
2211
- },
2212
- 'virtual:editorial_license': {
2213
- oer: ['oer'],
2214
- copyright: ['none_oer'],
2215
- without_license: ['none'],
2216
- },
2217
- 'virtual:oeh_lrt': {},
2218
- };
2219
- /*
2220
- This is a map from properties of a document to filter names
2221
- */
2222
- const PROPERTIES2FILTERS = new Map([
2223
- ['metadata.educationalContexts', 'ccm:educationalcontext'],
2224
- ['metadata.disciplines', 'virtual:taxonid'],
2225
- //["responsibility", "virtual:collection_id_primary"] // das zeigt auf "sammlungszugehörigkeit" und ist falsch
2226
- ]);
2227
- class EditorialLinkService {
2228
- constructor() {
2229
- this.env = inject(ConfigHelperService);
2230
- this.api = inject(MetaApiService);
2231
- this.typesLoaded$ = new BehaviorSubject(false);
2232
- this.api
2233
- .getMaterialTypesMapping()
2234
- .pipe(take(1))
2235
- .subscribe((types) => {
2236
- for (const [key, value] of Object.entries(types)) {
2237
- Issues2FilterNames.set(key, 'virtual:oeh_lrt');
2238
- MapValuesForFilter['virtual:oeh_lrt'][key] = value;
2239
- }
2240
- this.typesLoaded$.next(true);
2241
- });
2242
- }
2243
- openByReplicationsourceAndIssueTypeWithFilters(source, issue, selectedFilters) {
2244
- const filters = {};
2245
- filters['virtual:audit_filter'] = ['all'];
2246
- filters['ccm:oeh_publisher_combined'] = [source];
2247
- filters['virtual:editorial_exclusion'] = MapValuesForFilter['virtual:editorial_exclusion'][issue];
2248
- for (const [field, values] of Object.entries(selectedFilters)) {
2249
- if (values && values.length) {
2250
- const editorialFiltername = PROPERTIES2FILTERS.get(field);
2251
- filters[editorialFiltername] = values;
2252
- }
2253
- }
2254
- const theUrl = this.env.eduSharingPath + '/components/editorial-desk';
2255
- const params = new URLSearchParams();
2256
- params.set('mode', 'audit');
2257
- params.set('filters', JSON.stringify(filters));
2258
- window.open(`${theUrl}?${params}`, 'editor_frontend');
2259
- }
2260
- openByCollectionAndIssueType(collectionId, issueType, pageTitle) {
2261
- const filters = {};
2262
- filters['virtual:audit_filter'] = ['all'];
2263
- filters['virtual:editorial_exclusion'] = MapValuesForFilter['virtual:editorial_exclusion'][issueType];
2264
- filters['virtual:collection_id_primary'] = [collectionId];
2265
- const theUrl = this.env.eduSharingPath + '/components/editorial-desk';
2266
- const params = new URLSearchParams();
2267
- params.set('title', pageTitle);
2268
- params.set('mode', 'audit');
2269
- params.set('filters', JSON.stringify(filters));
2270
- window.open(`${theUrl}?${params}`, 'editor_frontend');
2271
- }
2272
- openByCollectionId(collectionId) {
2273
- const theUrl = this.env.eduSharingPath + '/components/editorial-desk';
2274
- const params = new URLSearchParams();
2275
- params.set('ids', collectionId);
2276
- params.set('mode', 'render');
2277
- window.open(`${theUrl}?${params}`, 'editor_frontend');
2278
- }
2279
- /**
2280
- * This method creates a link to the editorial desk with specific filters.
2281
- * It returns the URL to the editorial desk with the filters applied or null if the issueId is not mapped to a filter.
2282
- * With this we can render a link with an href attribute to the editorial desk in the frontend.
2283
- * @see the counts-with-history.component.scss how we style links only if their hrefs are not null
2284
- *
2285
- * @param sourceType The type of the source, e.g. "replicationSource" or "collection"
2286
- * @param sourceId The id of the source. This is the first column in the table.
2287
- * @param issueId The id of the issue. These are the other columns in the table.
2288
- */
2289
- createLinkForCountsWithHistory(sourceType, sourceId, issueId) {
2290
- const filters = {};
2291
- filters['virtual:audit_filter'] = ['all'];
2292
- // determine the "main" filter
2293
- if (sourceType === 'replicationSource') {
2294
- filters['ccm:oeh_publisher_combined'] = [sourceId];
2295
- }
2296
- else if (sourceType === 'collection') {
2297
- filters['virtual:collection_id_primary'] = [sourceId];
2298
- }
2299
- if (!Issues2FilterNames.has(issueId)) {
2300
- return null;
2301
- }
2302
- const filterName = Issues2FilterNames.get(issueId);
2303
- if (!filterName) {
2304
- // console.debug("No filter name found for issue id: " + issueId);
2305
- return null;
2306
- }
2307
- const filterValue = MapValuesForFilter[filterName][issueId];
2308
- if (!filterValue) {
2309
- // console.debug("No filter value found for issue id: " + issueId);
2310
- return null;
2279
+ https://reppners.github.io/ngx-cdk-dynamic-overlay-container/
2280
+ */
2281
+ this.progressSpinnerOverlayConfig['positionStrategy'] = this.overlayService.positionFlexibleConnected(this.el);
2311
2282
  }
2312
- filters[filterName] = filterValue;
2313
- const theUrl = this.env.eduSharingPath + '/components/editorial-desk';
2314
- const params = new URLSearchParams();
2315
- params.set('mode', 'audit');
2316
- params.set('filters', JSON.stringify(filters));
2317
- return `${theUrl}?${params}`;
2283
+ // Create Overlay for progress spinner
2284
+ this.overlayRef = this.overlayService.createOverlay(this.progressSpinnerOverlayConfig);
2318
2285
  }
2319
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorialLinkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2320
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorialLinkService, providedIn: 'root' }); }
2286
+ ngOnChanges(changes) {
2287
+ changes.displayProgressSpinner.currentValue
2288
+ ? this.overlayService.attachTemplatePortal(this.overlayRef, this.progressSpinnerRef, this.vcRef)
2289
+ : this.overlayRef.detach();
2290
+ }
2291
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProgressSpinnerComponent, deps: [{ token: i0.ViewContainerRef }, { token: OverlayService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
2292
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ProgressSpinnerComponent, isStandalone: true, selector: "metaqs2-progress-spinner", inputs: { color: "color", diameter: "diameter", strokeWidth: "strokeWidth", backdropEnabled: "backdropEnabled", positionGloballyCenter: "positionGloballyCenter", displayProgressSpinner: "displayProgressSpinner" }, viewQueries: [{ propertyName: "progressSpinnerRef", first: true, predicate: ["progressSpinnerRef"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<ng-template #progressSpinnerRef>\n <mat-spinner [color]=\"color\" [diameter]=\"diameter\" [strokeWidth]=\"strokeWidth\">\n\t</mat-spinner>\n</ng-template>", styles: [""], dependencies: [{ kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i2$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] }); }
2321
2293
  }
2322
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorialLinkService, decorators: [{
2323
- type: Injectable,
2294
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProgressSpinnerComponent, decorators: [{
2295
+ type: Component,
2296
+ args: [{ selector: 'metaqs2-progress-spinner', standalone: true, imports: [MatProgressSpinnerModule], template: "<ng-template #progressSpinnerRef>\n <mat-spinner [color]=\"color\" [diameter]=\"diameter\" [strokeWidth]=\"strokeWidth\">\n\t</mat-spinner>\n</ng-template>" }]
2297
+ }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: OverlayService }, { type: i0.ElementRef }], propDecorators: { color: [{
2298
+ type: Input
2299
+ }], diameter: [{
2300
+ type: Input
2301
+ }], strokeWidth: [{
2302
+ type: Input
2303
+ }], backdropEnabled: [{
2304
+ type: Input
2305
+ }], positionGloballyCenter: [{
2306
+ type: Input
2307
+ }], displayProgressSpinner: [{
2308
+ type: Input
2309
+ }], progressSpinnerRef: [{
2310
+ type: ViewChild,
2311
+ args: ['progressSpinnerRef', { static: true }]
2312
+ }] } });
2313
+
2314
+ class ScrollMarkerDirective {
2315
+ constructor() {
2316
+ this.element = inject(ElementRef);
2317
+ }
2318
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ScrollMarkerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2319
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: ScrollMarkerDirective, isStandalone: true, selector: "[metaqs2ScrollMarker]", ngImport: i0 }); }
2320
+ }
2321
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ScrollMarkerDirective, decorators: [{
2322
+ type: Directive,
2324
2323
  args: [{
2325
- providedIn: 'root',
2324
+ selector: '[metaqs2ScrollMarker]',
2325
+ standalone: true,
2326
2326
  }]
2327
- }], ctorParameters: () => [] });
2327
+ }] });
2328
2328
 
2329
2329
  const openCloseTimeout = 150;
2330
2330
  class QualityMatrixComponent {
2331
- constructor(metaApi, linkService, overlay, tooltipService) {
2332
- this.metaApi = metaApi;
2333
- this.linkService = linkService;
2334
- this.overlay = overlay;
2335
- this.tooltipService = tooltipService;
2331
+ constructor() {
2336
2332
  this.ref = inject(ElementRef);
2333
+ this.destroyRef = inject(DestroyRef);
2334
+ this.metaApi = inject(MetaApiService);
2335
+ this.linkService = inject(EditorialLinkService);
2336
+ this.overlay = inject(Overlay);
2337
+ this.tooltipService = inject(TooltipService);
2337
2338
  this.scrollLeft = signal(0);
2338
2339
  this.scrollWidth = signal(0);
2339
2340
  this.isLeftScrollable = computed(() => this.scrollLeft() > 0);
@@ -2345,13 +2346,34 @@ class QualityMatrixComponent {
2345
2346
  const viewportWidth = viewport.width;
2346
2347
  return this.scrollWidth() > viewportWidth && this.scrollLeft() + viewportWidth < this.scrollWidth();
2347
2348
  });
2348
- this.filteredColumns = [];
2349
- this.datatableColumns = [];
2350
- this.showHistoricalData = new FormControl({ value: false, disabled: true });
2351
- this.onlySourcesWithMaterial = new FormControl({ value: true, disabled: true });
2352
- this.isLoading = signal(true);
2349
+ this.filteredColumns = computed(() => {
2350
+ const allColumns = this.allColumns();
2351
+ const isOnlySourcesWithMaterialEnabled = this.isOnlySourcesWithMaterialEnabled();
2352
+ if (isOnlySourcesWithMaterialEnabled) {
2353
+ return allColumns.filter((c) => c.total > 0);
2354
+ }
2355
+ else {
2356
+ return allColumns;
2357
+ }
2358
+ });
2359
+ this.datatableColumns = computed(() => {
2360
+ return this.filteredColumns()
2361
+ .filter((c) => c.level !== 0)
2362
+ .map((c) => c.id);
2363
+ });
2364
+ this.isHistoricalDataEnabledFormField = new FormControl({ value: false, disabled: true });
2365
+ this.isHistoricalDataEnabled = toSignal(this.isHistoricalDataEnabledFormField.valueChanges);
2366
+ this.isOnlySourcesWithMaterialEnabledFormField = new FormControl({ value: true, disabled: true });
2367
+ this.isOnlySourcesWithMaterialEnabled = toSignal(this.isOnlySourcesWithMaterialEnabledFormField.valueChanges);
2368
+ this.categoryControls = new FormRecord({});
2369
+ this.loadingCount = signal(0);
2370
+ this.isLoading = computed(() => this.loadingCount() > 0);
2353
2371
  this.categoryFilterValues = new Map();
2372
+ this.refresh$ = new Subject();
2354
2373
  this.recentQualityMatrix$ = new BehaviorSubject({ columns: [], rows: [] });
2374
+ this.recentQualityMatrix = toSignal(this.recentQualityMatrix$, {
2375
+ initialValue: { columns: [], rows: [] },
2376
+ });
2355
2377
  this.pastQualityMatrix$ = new BehaviorSubject({ columns: [], rows: [] });
2356
2378
  this.range = new FormGroup({
2357
2379
  start: new FormControl(),
@@ -2360,17 +2382,18 @@ class QualityMatrixComponent {
2360
2382
  this.tooltips = new Map();
2361
2383
  this.DateTime = DateTime;
2362
2384
  this.pageTitle = 'Quality Matrix';
2363
- // a FormRecord has to be initialized with one source to determine its type :-(
2364
- this.categoryControls = new FormRecord({ dummy: new FormControl([], { nonNullable: true }) });
2365
- this.categoryControls.removeControl('dummy', { emitEvent: false });
2366
- this.registerCategoryFilters();
2367
- this.registerDateRangeFilter();
2368
- // TODO: consider a register() functions
2369
- this.onlySourcesWithMaterial.valueChanges.pipe(takeUntilDestroyed()).subscribe((onlyWithMaterial) => {
2370
- this.filterTableBySourcesWithMaterial(onlyWithMaterial);
2385
+ this.allColumns = computed(() => this.recentQualityMatrix()?.columns.toSorted((a, b) => a.label.localeCompare(b.label)));
2386
+ this.sourceColumns = computed(() => this.datatableColumns().map((c) => c + '_source'));
2387
+ this.currentColumns = computed(() => this.datatableColumns().map((c) => c + '_current'));
2388
+ this.pastColumns = computed(() => this.datatableColumns().map((c) => c + '_past'));
2389
+ this.allDataColumns = computed(() => {
2390
+ const pastColumns = this.pastColumns();
2391
+ const currentColumns = this.currentColumns();
2392
+ if (this.isHistoricalDataEnabled()) {
2393
+ return currentColumns.flatMap((e, i) => [pastColumns[i], e]);
2394
+ }
2395
+ return currentColumns;
2371
2396
  });
2372
- this.onLoadedDataChanges();
2373
- //this.loadDataWithCurrentlySelectedFilters();
2374
2397
  }
2375
2398
  ngAfterViewChecked() {
2376
2399
  this.onScroll();
@@ -2378,54 +2401,57 @@ class QualityMatrixComponent {
2378
2401
  filterIdent(_index, item) {
2379
2402
  return item.key;
2380
2403
  }
2381
- get qualityMatrix() {
2382
- return this.recentQualityMatrix$.value;
2404
+ loadData(categories, date) {
2405
+ return of(undefined).pipe(tap(() => this.loadingCount.update((it) => it + 1)), switchMap(() => this.metaApi
2406
+ .getQualityMatrixWithFiltersV2([
2407
+ ...this.transformCategoryFilters(categories),
2408
+ {
2409
+ field: 'asOf',
2410
+ values: [
2411
+ {
2412
+ id: date.toISO({
2413
+ includeOffset: false,
2414
+ }),
2415
+ label: '',
2416
+ },
2417
+ ],
2418
+ },
2419
+ ])
2420
+ .pipe(take(1))), finalize(() => this.loadingCount.update((it) => it - 1)));
2421
+ }
2422
+ transformCategoryFilters(categories) {
2423
+ return Object.entries(categories)
2424
+ .filter((pair) => !!pair[1]?.length)
2425
+ .map(([field, values]) => ({
2426
+ field,
2427
+ values: values.map((value) => ({ id: value, label: '' })),
2428
+ }));
2383
2429
  }
2384
- get sourceColumns() {
2385
- return this.datatableColumns.map((c) => c + '_source');
2430
+ loadPastData(categories, date) {
2431
+ return of(undefined).pipe(switchMap(() => this.loadData(categories, date)));
2386
2432
  }
2387
- get currentColumns() {
2388
- return this.datatableColumns.map((c) => c + '_current');
2433
+ loadCurrentData(categories, date) {
2434
+ return of(undefined).pipe(switchMap(() => this.loadData(categories, date)));
2389
2435
  }
2390
- get pastColumns() {
2391
- return this.datatableColumns.map((c) => c + '_past');
2436
+ openEditLink(source, issue) {
2437
+ return this.linkService.openByReplicationsourceAndIssueTypeWithFilters(source, issue, this.categoryControls.value);
2392
2438
  }
2393
- get allDataColumns() {
2394
- if (this.showHistoricalData.value) {
2395
- return this.pastColumns.flatMap((e, i) => [e, this.currentColumns[i]]);
2396
- }
2397
- return this.currentColumns;
2439
+ // see https://github.com/angular/components/issues/8361#issuecomment-345804954
2440
+ columnIdent(_index, col) {
2441
+ return col.id;
2398
2442
  }
2399
- filterTableBySourcesWithMaterial(onlyWith) {
2400
- const allColumns = this.recentQualityMatrix$.value.columns.toSorted((a, b) => a.label.localeCompare(b.label));
2401
- // avoid filtering when not necessary
2402
- this.filteredColumns = onlyWith ? allColumns.filter((c) => c.total > 0) : allColumns;
2403
- this.datatableColumns = this.filteredColumns.map((c) => c.id);
2443
+ refresh() {
2444
+ this.refresh$.next();
2404
2445
  }
2405
- registerDateRangeFilter() {
2406
- this.range.valueChanges.pipe(takeUntilDestroyed()).subscribe(() => {
2407
- this.loadDataWithCurrentlySelectedFilters();
2408
- });
2409
- this.metaApi.getTimerangeFilter().subscribe((rangeFilter) => {
2410
- if (rangeFilter) {
2411
- const startDate = DateTime.fromISO(rangeFilter.values.find((v) => v.id === 'rangeStart')?.label, {
2412
- zone: 'utc',
2413
- });
2414
- const endDate = DateTime.fromISO(rangeFilter.values.find((v) => v.id === 'rangeEnd')?.label, { zone: 'utc' });
2415
- //toggle the emitEvent to initially load the data or not
2416
- this.range.setControl('start', new FormControl(startDate, { nonNullable: true }), {
2417
- emitEvent: false,
2418
- });
2419
- this.range.setControl('end', new FormControl(endDate, { nonNullable: true }), { emitEvent: true });
2420
- }
2421
- });
2446
+ getPastColumn(columnId) {
2447
+ return this.pastQualityMatrix$.value?.columns.find((c) => c.id === columnId);
2422
2448
  }
2423
- registerCategoryFilters() {
2449
+ ngOnInit() {
2424
2450
  this.metaApi
2425
2451
  .getCategoryFilters()
2426
- .pipe(take(1))
2427
- .subscribe((filters) => {
2452
+ .pipe(take(1), tap((filters) => {
2428
2453
  filters.forEach((filter) => {
2454
+ // do not emit the event when setting the control to prevent unnecessary valueChanges events
2429
2455
  this.categoryControls.addControl(filter.field, new FormControl([], { nonNullable: true }), {
2430
2456
  emitEvent: false,
2431
2457
  });
@@ -2433,99 +2459,73 @@ class QualityMatrixComponent {
2433
2459
  return a.label.localeCompare(b.label);
2434
2460
  }));
2435
2461
  });
2436
- });
2437
- this.categoryControls.valueChanges
2438
- .pipe(takeUntilDestroyed())
2439
- .subscribe(() => this.loadDataWithCurrentlySelectedFilters());
2440
- }
2441
- onLoadedDataChanges() {
2442
- this.recentQualityMatrix$
2443
- .pipe(takeUntilDestroyed(), filter((qm) => qm !== null), tap(() => this.filterTableBySourcesWithMaterial(this.onlySourcesWithMaterial.value)))
2462
+ // emit the current value of the form group once to trigger the valueChanges observable
2463
+ this.categoryControls.setValue(this.categoryControls.value, {
2464
+ emitEvent: true,
2465
+ });
2466
+ }), takeUntilDestroyed(this.destroyRef))
2444
2467
  .subscribe();
2445
- }
2446
- loadDataForStart() {
2447
- if (this.range.controls.start?.value) {
2448
- const body = this.getCurrentFilterValues();
2449
- body.push({
2450
- field: 'asOf',
2451
- values: [{ id: this.range.controls.start.value.toISO({ includeOffset: false }), label: '' }],
2468
+ this.metaApi
2469
+ .getTimerangeFilter()
2470
+ .pipe(filter((rangeFilter) => !!rangeFilter), tap((rangeFilter) => {
2471
+ const startDate = DateTime.fromISO(rangeFilter.values.find((v) => v.id === 'rangeStart')?.label, {
2472
+ zone: 'utc',
2452
2473
  });
2453
- return this.metaApi.getQualityMatrixWithFiltersV2(body).pipe(take(1));
2454
- }
2455
- return of(null);
2456
- }
2457
- loadDataForEnd() {
2458
- const body = this.getCurrentFilterValues();
2459
- body.push({
2460
- field: 'asOf',
2461
- values: [{ id: this.range.controls.end.value.toISO({ includeOffset: false }), label: '' }],
2462
- });
2463
- return this.metaApi.getQualityMatrixWithFiltersV2(body).pipe(take(1));
2464
- }
2465
- getCurrentFilterValues() {
2466
- const body = [];
2467
- for (const [field, values] of Object.entries(this.categoryControls.value)) {
2468
- let requestValues = [];
2469
- if (values && values.length) {
2470
- requestValues = values.map((value) => ({ id: value, label: '' }));
2471
- body.push({ field, values: requestValues });
2472
- }
2473
- }
2474
- return body;
2475
- }
2476
- loadDataWithCurrentlySelectedFilters() {
2477
- /*
2478
- consider using an intermediate Subject with a switchMap pipe
2479
- to prevent that older ( longer running ) requests overwrite newer ones
2480
- see https://stackoverflow.com/questions/64427629/how-to-use-rxjs-to-cancel-previous-http-requests-in-an-angular-service/64490155#64490155
2481
- */
2482
- this.isLoading.set(true);
2483
- forkJoin({
2484
- pastQm: this.loadDataForStart(),
2485
- currentQm: this.loadDataForEnd(),
2486
- })
2487
- .pipe(finalize(() => {
2488
- this.isLoading.set(false);
2489
- }), tap(({ pastQm: _, currentQm }) => {
2490
- this.datatableColumns = currentQm.columns.filter((c) => c.level !== 0).map((c) => c.id);
2491
- }))
2492
- .subscribe(({ pastQm, currentQm }) => {
2474
+ const endDate = DateTime.fromISO(rangeFilter.values.find((v) => v.id === 'rangeEnd')?.label, {
2475
+ zone: 'utc',
2476
+ });
2477
+ this.range.setControl('start', new FormControl(startDate, { nonNullable: true }), {
2478
+ emitEvent: false,
2479
+ });
2480
+ this.range.setControl('end', new FormControl(endDate, { nonNullable: true }), {
2481
+ emitEvent: true,
2482
+ });
2483
+ }), takeUntilDestroyed(this.destroyRef))
2484
+ .subscribe();
2485
+ combineLatest([this.categoryControls.valueChanges, this.range.valueChanges, this.refresh$])
2486
+ .pipe(filter((data) => !!data[0] && !!data[1].end?.isValid), throttleTime(500), map(([categories, range]) => [categories, range.end]), switchMap(([categories, end]) => this.loadCurrentData(categories, end)), tap((currentQm) => {
2493
2487
  this.recentQualityMatrix$.next(currentQm);
2488
+ }), takeUntilDestroyed(this.destroyRef))
2489
+ .subscribe();
2490
+ let pastDataSubscription;
2491
+ const pastData$ = combineLatest([this.categoryControls.valueChanges, this.range.valueChanges, this.refresh$]).pipe(filter((data) => !!data[0] && !!data[1].start?.isValid), throttleTime(500), map(([categories, range]) => [categories, range.start]), switchMap(([categories, start]) => this.loadPastData(categories, start)), tap((pastQm) => {
2494
2492
  this.pastQualityMatrix$.next(pastQm);
2493
+ }), takeUntilDestroyed(this.destroyRef));
2494
+ this.isHistoricalDataEnabledFormField.valueChanges
2495
+ .pipe(tap((isEnabled) => {
2496
+ if (isEnabled) {
2497
+ pastDataSubscription = pastData$.subscribe();
2498
+ this.categoryControls.setValue(this.categoryControls.value, {
2499
+ emitEvent: true,
2500
+ });
2501
+ this.range.setValue(this.range.value, {
2502
+ emitEvent: true,
2503
+ });
2504
+ this.refresh$.next();
2505
+ }
2506
+ else {
2507
+ pastDataSubscription?.unsubscribe();
2508
+ }
2509
+ }), takeUntilDestroyed(this.destroyRef))
2510
+ .subscribe();
2511
+ this.refresh$.next();
2512
+ this.isOnlySourcesWithMaterialEnabledFormField.setValue(this.isOnlySourcesWithMaterialEnabledFormField.value, {
2513
+ emitEvent: true,
2495
2514
  });
2496
2515
  }
2497
- openEditLink(source, issue) {
2498
- return this.linkService.openByReplicationsourceAndIssueTypeWithFilters(source, issue, this.categoryControls.value);
2499
- }
2500
- // see https://github.com/angular/components/issues/8361#issuecomment-345804954
2501
- columnIdent(_index, col) {
2502
- return col.id;
2503
- }
2504
- async refresh() {
2505
- //or should we reset all Filter?
2506
- this.loadDataWithCurrentlySelectedFilters();
2507
- }
2508
- getPastColumn(columnId) {
2509
- return this.pastQualityMatrix$.value?.columns.find((c) => c.id === columnId);
2510
- }
2511
2516
  getTrend(row, column) {
2512
- if (this.pastQualityMatrix$.value === null) {
2517
+ if (this.pastQualityMatrix$.value === null || this.pastQualityMatrix$.value.columns.length === 0) {
2513
2518
  return {};
2514
2519
  }
2515
- if (this.pastQualityMatrix$.value.columns.length > 0) {
2516
- const past_row = this.pastQualityMatrix$?.value.rows.find((pr) => pr.meta.id == row.meta.id);
2517
- const past_column = this.pastQualityMatrix$.value.columns.find((c) => c.id == column.id);
2518
- if (!past_row || !past_column) {
2519
- return {};
2520
- }
2521
- const delta = Math.floor((100 * row.counts[column.id].sufficient) / column.total -
2522
- (100 * past_row.counts[column.id].sufficient) / past_column.total);
2523
- const trend = delta === 0 ? 'trending_flat' : delta < 0 ? 'trending_down' : 'trending_up';
2524
- return { delta, trend };
2525
- }
2526
- else {
2520
+ const past_row = this.pastQualityMatrix$?.value.rows.find((pr) => pr.meta.id == row.meta.id);
2521
+ const past_column = this.pastQualityMatrix$.value.columns.find((c) => c.id == column.id);
2522
+ if (!past_row || !past_column) {
2527
2523
  return {};
2528
2524
  }
2525
+ const delta = Math.floor((100 * row.counts[column.id].sufficient) / column.total -
2526
+ (100 * past_row.counts[column.id].sufficient) / past_column.total);
2527
+ const trend = delta === 0 ? 'trending_flat' : delta < 0 ? 'trending_down' : 'trending_up';
2528
+ return { delta, trend };
2529
2529
  }
2530
2530
  getDonutSlices(row, column) {
2531
2531
  const sufficientTotal = row.counts[column.id].sufficient;
@@ -2654,8 +2654,8 @@ class QualityMatrixComponent {
2654
2654
  this.scrollLeft.set(scrollingElement.scrollLeft);
2655
2655
  this.scrollWidth.set(scrollingElement.scrollWidth);
2656
2656
  }
2657
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: QualityMatrixComponent, deps: [{ token: MetaApiService }, { token: EditorialLinkService }, { token: i1$3.Overlay }, { token: TooltipService }], target: i0.ɵɵFactoryTarget.Component }); }
2658
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: QualityMatrixComponent, isStandalone: true, selector: "metaqs2-quality-matrix-v2", inputs: { pageTitle: "pageTitle" }, host: { listeners: { "window:scroll": "onScroll()", "window:resize": "onScroll()" } }, providers: [TooltipService], viewQueries: [{ propertyName: "issueTypeHeader", first: true, predicate: ["issueType"], descendants: true, read: ElementRef, static: true }, { propertyName: "scrollMarkers", predicate: ScrollMarkerDirective, descendants: true }], ngImport: i0, template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title>\n Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{isLoading() ? \": Lade neue Daten.\" : \"\"}}</mat-card-title\n >\n </mat-card-header>\n <mat-card-content class=\"toolbar\">\n <metaqs2-qm-filter *ngFor=\"let filter of categoryControls.controls | keyvalue; trackBy: filterIdent\"\n [options]=\"categoryFilterValues.get(filter.key)\"\n [inputFormControl]=\"filter.value\"\n [label] = \"'filter.' + filter.key | translate\" />\n <div class=\"actionbar\">\n <mat-slide-toggle [disabled]=\"isLoading()\" labelPosition=\"before\" [formControl]=\"onlySourcesWithMaterial\" id=\"onlySourcesWithMaterial\">\n show only sources with material\n </mat-slide-toggle>\n <div style=\"flex: 1 1 auto\"></div>\n <metaqs2-datepicker *ngIf=\"showHistoricalData.value\" [disabled]=\"isLoading()\" [inputGroup]=\"range\" />\n <mat-slide-toggle [disabled]=\"isLoading()\" labelPosition=\"before\" [formControl]=\"showHistoricalData\" id=\"showHistoricalData\">\n show historical data\n </mat-slide-toggle>\n <button\n mat-icon-button\n color=\"primary\"\n [disabled]=\"isLoading\"\n (click)=\"refresh()\"\n matTooltip=\"Aktualisiere den IST-Stand\"\n matTooltipShowDelay=\"500\"\n >\n <mat-icon>refresh</mat-icon>\n </button>\n <div style=\"flex: 0 0 {{scroller.getBoundingClientRect().width}}px\"></div>\n <div class=\"scroll-controller\" #scroller> <!-- put the whole toolbar in a fixed container (MQS- -->\n <button mat-raised-button (click)=\"scrollToLeft()\" [disabled]=\"!isLeftScrollable()\" class=\"scroll-button\">\n <mat-icon style=\"margin: 0\">chevron_left</mat-icon>\n </button>\n <button mat-raised-button (click)=\"scrollToRight()\" [disabled]=\"!isRightScrollable()\" class=\"scroll-button\">\n <mat-icon style=\"margin: 0\">chevron_right</mat-icon>\n </button>\n </div>\n </div>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentQualityMatrix$.value.rows\" class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"row-header\" sticky>\n <th rowspan=\"2\" mat-header-cell *matHeaderCellDef #issueType>Issue Type</th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n matTooltip=\"{{row.meta.alt_label}}\"\n class=\"row-header mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{\"quality_matrix.\" + row.meta.label | translate }}\n </td>\n </ng-container>\n <!-- one column for the source -->\n <ng-container *ngFor=\"let col of filteredColumns; trackBy:columnIdent\" [matColumnDef]=\"col.id + '_source'\">\n <th [attr.colspan]=\"showHistoricalData.value?2:1\" metaqs2ScrollMarker mat-header-cell *matHeaderCellDef matTooltip=\"{{col.altLabel}}\">{{col.label}}</th>\n </ng-container>\n <!-- /source -->\n <!-- current Data Columns -->\n <ng-container *ngFor=\"let column of filteredColumns; trackBy:columnIdent\" [matColumnDef]=\"column.id + '_current'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"{{column.altLabel}}\">{{ range.controls.end.value?.toLocaleString(DateTime.DATE_SHORT) }} <br>({{column.total}})</th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\" #cell (mouseover)=\"showTooltip(row, column, cell)\" (mouseleave)=\"hideTooltip(cell)\">\n <a *ngIf=\"column.total > 0 else emptyDiv\" class=\"chart-container\" (click)=\"openEditLink( column.label, row.meta.label)\">\n <div>\n <metaqs2-donut-chart [data]=\"getDonutSlices(row, column)\" [borderSize]=\"25\"></metaqs2-donut-chart>\n </div>\n </a>\n <ng-template #emptyDiv>\n <div>-</div>\n </ng-template>\n </td>\n </ng-container>\n <!-- /current Data Columns -->\n <!-- past Data Columns -->\n <ng-container *ngIf=\"showHistoricalData.value\">\n <ng-container *ngFor=\"let column of filteredColumns; trackBy:columnIdent\" [matColumnDef]=\"column.id + '_past'\">\n <th class=\"historic-data-cell\" mat-header-cell\n *matHeaderCellDef>{{ range.controls.start.value?.toLocaleString(DateTime.DATE_SHORT) }}\n <br>{{ getPastColumn(column.id)?.total }}\n </th>\n <td class=\"historic-data-cell\" mat-cell *matCellDef=\"let row\">\n <ng-container *ngIf=\"getTrend(row, column) as trend\">\n <span [ngClass]=\"trend.trend\">\n <mat-icon aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" />\n {{ trend.delta }}\n </span>\n </ng-container>\n\n </td>\n </ng-container>\n </ng-container>\n <!-- /past Data Columns -->\n\n <!-- Generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['row-header'].concat( sourceColumns); sticky: true;\"></tr>\n <tr mat-header-row *matHeaderRowDef=\"allDataColumns; sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['row-header'].concat(allDataColumns)\"></tr>\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}mat-card-actions>mat-slide-toggle{margin-left:20px}.row{flex-grow:1;display:flex;align-items:center}table{width:100%;overflow-y:auto}table .scroll{flex-grow:1;overflow-y:auto}table th{vertical-align:top;padding:.375rem}table th:not(:last-child){border-right:1px solid #e4e4e4}table tr:first-child>th:first-child{text-align:left}table td:first-child{text-align:left}.cell{flex:1}.mat-mdc-cell{padding-top:5px}.mat-mdc-cell,.mat-mdc-header-cell{padding-left:5px;text-align:center}.mat-mdc-cell a.chart-container,.mat-mdc-header-cell a.chart-container{display:flex;justify-content:center}.mat-mdc-cell .trending_up,.mat-mdc-header-cell .trending_up{color:#4abeff}.mat-mdc-cell .trending_down,.mat-mdc-header-cell .trending_down{color:#c20808}.recent-data-cell,.mat-column-row-header{border-right:1px solid #e4e4e4}.mat-header-cell-label{color:#000;padding-left:30px;padding-right:30px;justify-content:left;border-bottom:1px solid #e4e4e4;font-style:normal;font-weight:500;font-size:110%;background:#ddf0fb;text-align:left}.mat-header-cell-label>div{display:flex;font-weight:700;font-style:normal;justify-content:left}.mat-header-cell-small{padding-left:5px;padding-right:5px;justify-content:left;font-style:normal;font-weight:400;font-size:105%;background:#ddf0fb;border-top:1px solid #e4e4e4;border-bottom:1px solid #e4e4e4}.mat-mdc-cell a{cursor:pointer;display:flex;align-items:center;justify-content:left}.mat-mdc-cell a>mat-icon{padding-right:5px;font-size:22px;height:20px;opacity:.75}.mat-mdc-cell a>mat-icon:hover,.mat-mdc-cell a>mat-icon:focus{text-decoration:none}.mat-mdc-cell .number{display:flex;height:47px;justify-content:left;align-items:center;padding-left:15px}.mat-mdc-cell .row-header{display:flex;height:47px;max-height:47px;justify-content:left;align-items:center;padding-left:15px}.mat-mdc-cell .row-header-sum{display:flex;height:47px;max-height:47px;justify-content:left;align-items:center;border-right:5px solid #bdbdbd}.mat-mdc-card{width:100%;box-shadow:none}.mat-mdc-card ::ng-deep mat-card-header{align-items:center}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text{flex-grow:1;margin:0}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text mat-card-title{padding-top:20px;font-size:120%}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text mat-card-title .count{font-size:80%;color:#888}.mat-mdc-card .source-header{font-style:normal;font-weight:400;font-size:20px;height:30px;width:60%}.mat-mdc-card .source-header .robot-explanation{font-size:15px}.mat-mdc-card .scroll{flex-grow:1;overflow-y:auto}.mat-header-cell-scope{color:#545454}.mat-mdc-header-row{height:70px;max-height:70px;min-height:56px}:host{overflow:auto}:host ::ng-deep thead{border:10px solid #ff0000;position:relative;z-index:1}.mat-cell-level-1{padding-left:20px!important}.mat-cell-level-2{padding-left:40px!important}.mat-cell-level-3{padding-left:60px!important}.mat-cell-level-4{padding-left:80px!important}.mat-cell-level-5{padding-left:100px!important}.mat-cell-level-6{padding-left:120px!important}.mat-cell-level-7{padding-left:140px!important}.mat-cell-level-8{padding-left:160px!important}.actionbar{flex:1 1 auto;display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:.5rem}.scroll-controller{position:fixed;right:.5rem;z-index:100;display:flex;flex-direction:row;justify-content:space-between;align-items:center;gap:.5rem}.scroll-button{min-width:0;padding-left:.25rem;padding-right:.25rem;text-align:center;height:1.75rem}.toolbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:stretch;gap:.5rem}\n"], dependencies: [{ kind: "component", type: MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "component", type: MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "directive", type: MatCardContent, selector: "mat-card-content" }, { kind: "component", type: QualityMatrixFilterComponent, selector: "metaqs2-qm-filter", inputs: ["options", "inputFormControl", "label", "multiple"], outputs: ["changedFilters"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$3.TranslatePipe, name: "translate" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: DatepickerComponent, selector: "metaqs2-datepicker", inputs: ["disabled", "inputGroup"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ProgressSpinnerComponent, selector: "metaqs2-progress-spinner", inputs: ["color", "diameter", "strokeWidth", "backdropEnabled", "positionGloballyCenter", "displayProgressSpinner"] }, { kind: "component", type: MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: MatCellDef, selector: "[matCellDef]" }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: DonutChartComponent, selector: "metaqs2-donut-chart", inputs: ["radius", "viewBox", "borderSize", "strokeWidth", "data"] }, { kind: "directive", type: ScrollMarkerDirective, selector: "[metaqs2ScrollMarker]" }] }); }
2657
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: QualityMatrixComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2658
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: QualityMatrixComponent, isStandalone: true, selector: "metaqs2-quality-matrix-v2", inputs: { pageTitle: "pageTitle" }, host: { listeners: { "window:scroll": "onScroll()", "window:resize": "onScroll()" } }, providers: [TooltipService], viewQueries: [{ propertyName: "issueTypeHeader", first: true, predicate: ["issueType"], descendants: true, read: ElementRef, static: true }, { propertyName: "scrollMarkers", predicate: ScrollMarkerDirective, descendants: true }], ngImport: i0, template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title>Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{isLoading() ? \": Lade neue Daten.\" : \"\"}}</mat-card-title>\n </mat-card-header>\n <mat-card-content class=\"toolbar\">\n <metaqs2-qm-filter *ngFor=\"let filter of categoryControls.controls | keyvalue; trackBy: filterIdent\"\n [options]=\"categoryFilterValues.get(filter.key)\"\n [inputFormControl]=\"filter.value\"\n [label] = \"'filter.' + filter.key | translate\" />\n <div class=\"actionbar\">\n <mat-slide-toggle [disabled]=\"isLoading()\" labelPosition=\"before\" [formControl]=\"isOnlySourcesWithMaterialEnabledFormField\" id=\"onlySourcesWithMaterial\">\n show only sources with material\n </mat-slide-toggle>\n <div style=\"flex: 1 1 auto\"></div>\n <metaqs2-datepicker *ngIf=\"isHistoricalDataEnabled()\" [disabled]=\"isLoading()\" [inputGroup]=\"range\" />\n <mat-slide-toggle [disabled]=\"isLoading()\" labelPosition=\"before\" [formControl]=\"isHistoricalDataEnabledFormField\" id=\"showHistoricalData\">\n show historical data\n </mat-slide-toggle>\n <button\n mat-icon-button\n color=\"primary\"\n [disabled]=\"isLoading()\"\n (click)=\"refresh()\"\n matTooltip=\"Aktualisiere den IST-Stand\"\n matTooltipShowDelay=\"500\"\n >\n <mat-icon>refresh</mat-icon>\n </button>\n <div style=\"flex: 0 0 {{scroller.getBoundingClientRect().width}}px\"></div>\n <div class=\"scroll-controller\" #scroller> <!-- put the whole toolbar in a fixed container (MQS- -->\n <button mat-raised-button (click)=\"scrollToLeft()\" [disabled]=\"!isLeftScrollable()\" class=\"scroll-button\">\n <mat-icon style=\"margin: 0\">chevron_left</mat-icon>\n </button>\n <button mat-raised-button (click)=\"scrollToRight()\" [disabled]=\"!isRightScrollable()\" class=\"scroll-button\">\n <mat-icon style=\"margin: 0\">chevron_right</mat-icon>\n </button>\n </div>\n </div>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentQualityMatrix().rows\" class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"row-header\" sticky>\n <th rowspan=\"2\" mat-header-cell *matHeaderCellDef #issueType>Issue Type</th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n matTooltip=\"{{row.meta.alt_label}}\"\n class=\"row-header mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{\"quality_matrix.\" + row.meta.label | translate }}\n </td>\n </ng-container>\n <!-- one column for the source -->\n <ng-container *ngFor=\"let col of filteredColumns(); trackBy:columnIdent\" [matColumnDef]=\"col.id + '_source'\">\n <th [attr.colspan]=\"isHistoricalDataEnabled() ? 2 : 1\" metaqs2ScrollMarker mat-header-cell *matHeaderCellDef matTooltip=\"{{col.altLabel}}\">{{col.label}}</th>\n </ng-container>\n <!-- /source -->\n <!-- current Data Columns -->\n <ng-container *ngFor=\"let column of filteredColumns(); trackBy:columnIdent\" [matColumnDef]=\"column.id + '_current'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"{{column.altLabel}}\">{{ range.controls.end.value?.toLocaleString(DateTime.DATE_SHORT) }} <br>({{column.total}})</th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\" #cell (mouseover)=\"showTooltip(row, column, cell)\" (mouseleave)=\"hideTooltip(cell)\">\n <a *ngIf=\"column.total > 0 else emptyDiv\" class=\"chart-container\" (click)=\"openEditLink( column.label, row.meta.label)\">\n <div>\n <metaqs2-donut-chart [data]=\"getDonutSlices(row, column)\" [borderSize]=\"25\"></metaqs2-donut-chart>\n </div>\n </a>\n <ng-template #emptyDiv>\n <div>-</div>\n </ng-template>\n </td>\n </ng-container>\n <!-- /current Data Columns -->\n <!-- past Data Columns -->\n <ng-container *ngIf=\"isHistoricalDataEnabled()\">\n <ng-container *ngFor=\"let column of filteredColumns(); trackBy:columnIdent\" [matColumnDef]=\"column.id + '_past'\">\n <th class=\"historic-data-cell\" mat-header-cell\n *matHeaderCellDef>{{ range.controls.start.value?.toLocaleString(DateTime.DATE_SHORT) }}\n <br>{{ getPastColumn(column.id)?.total }}\n </th>\n <td class=\"historic-data-cell\" mat-cell *matCellDef=\"let row\">\n <ng-container *ngIf=\"getTrend(row, column) as trend\">\n <span [ngClass]=\"trend.trend\">\n <mat-icon aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" />\n {{ trend.delta }}\n </span>\n </ng-container>\n\n </td>\n </ng-container>\n </ng-container>\n <!-- /past Data Columns -->\n\n <!-- Generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['row-header'].concat(sourceColumns()); sticky: true;\"></tr>\n <tr mat-header-row *matHeaderRowDef=\"allDataColumns(); sticky: true;\" [hidden]=\"!isHistoricalDataEnabled()\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['row-header'].concat(allDataColumns())\"></tr>\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}mat-card-actions>mat-slide-toggle{margin-left:20px}.row{flex-grow:1;display:flex;align-items:center}table{width:100%;overflow-y:auto}table .scroll{flex-grow:1;overflow-y:auto}table th{vertical-align:top;padding:.375rem}table th:not(:last-child){border-right:1px solid #e4e4e4}table tr:first-child>th:first-child{text-align:left}table td:first-child{text-align:left}.cell{flex:1}.mat-mdc-cell{padding-top:5px}.mat-mdc-cell,.mat-mdc-header-cell{padding-left:5px;text-align:center}.mat-mdc-cell a.chart-container,.mat-mdc-header-cell a.chart-container{display:flex;justify-content:center}.mat-mdc-cell .trending_up,.mat-mdc-header-cell .trending_up{color:#4abeff}.mat-mdc-cell .trending_down,.mat-mdc-header-cell .trending_down{color:#c20808}.recent-data-cell,.mat-column-row-header{border-right:1px solid #e4e4e4}.mat-header-cell-label{color:#000;padding-left:30px;padding-right:30px;justify-content:left;border-bottom:1px solid #e4e4e4;font-style:normal;font-weight:500;font-size:110%;background:#ddf0fb;text-align:left}.mat-header-cell-label>div{display:flex;font-weight:700;font-style:normal;justify-content:left}.mat-header-cell-small{padding-left:5px;padding-right:5px;justify-content:left;font-style:normal;font-weight:400;font-size:105%;background:#ddf0fb;border-top:1px solid #e4e4e4;border-bottom:1px solid #e4e4e4}.mat-mdc-cell a{cursor:pointer;display:flex;align-items:center;justify-content:left}.mat-mdc-cell a>mat-icon{padding-right:5px;font-size:22px;height:20px;opacity:.75}.mat-mdc-cell a>mat-icon:hover,.mat-mdc-cell a>mat-icon:focus{text-decoration:none}.mat-mdc-cell .number{display:flex;height:47px;justify-content:left;align-items:center;padding-left:15px}.mat-mdc-cell .row-header{display:flex;height:47px;max-height:47px;justify-content:left;align-items:center;padding-left:15px}.mat-mdc-cell .row-header-sum{display:flex;height:47px;max-height:47px;justify-content:left;align-items:center;border-right:5px solid #bdbdbd}.mat-mdc-card{width:100%;box-shadow:none}.mat-mdc-card ::ng-deep mat-card-header{align-items:center}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text{flex-grow:1;margin:0}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text mat-card-title{padding-top:20px;font-size:120%}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text mat-card-title .count{font-size:80%;color:#888}.mat-mdc-card .source-header{font-style:normal;font-weight:400;font-size:20px;height:30px;width:60%}.mat-mdc-card .source-header .robot-explanation{font-size:15px}.mat-mdc-card .scroll{flex-grow:1;overflow-y:auto}.mat-header-cell-scope{color:#545454}.mat-mdc-header-row{height:70px;max-height:70px;min-height:56px}:host{overflow:auto}:host ::ng-deep thead{border:10px solid #ff0000;position:relative;z-index:1}.mat-cell-level-1{padding-left:20px!important}.mat-cell-level-2{padding-left:40px!important}.mat-cell-level-3{padding-left:60px!important}.mat-cell-level-4{padding-left:80px!important}.mat-cell-level-5{padding-left:100px!important}.mat-cell-level-6{padding-left:120px!important}.mat-cell-level-7{padding-left:140px!important}.mat-cell-level-8{padding-left:160px!important}.actionbar{flex:1 1 auto;display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:.5rem}.scroll-controller{position:fixed;right:.5rem;z-index:100;display:flex;flex-direction:row;justify-content:space-between;align-items:center;gap:.5rem}.scroll-button{min-width:0;padding-left:.25rem;padding-right:.25rem;text-align:center;height:1.75rem}.toolbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:stretch;gap:.5rem}\n"], dependencies: [{ kind: "component", type: MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "component", type: MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "directive", type: MatCardContent, selector: "mat-card-content" }, { kind: "component", type: QualityMatrixFilterComponent, selector: "metaqs2-qm-filter", inputs: ["options", "inputFormControl", "label", "multiple"], outputs: ["changedFilters"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$3.TranslatePipe, name: "translate" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: DatepickerComponent, selector: "metaqs2-datepicker", inputs: ["disabled", "inputGroup"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ProgressSpinnerComponent, selector: "metaqs2-progress-spinner", inputs: ["color", "diameter", "strokeWidth", "backdropEnabled", "positionGloballyCenter", "displayProgressSpinner"] }, { kind: "component", type: MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: MatCellDef, selector: "[matCellDef]" }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: DonutChartComponent, selector: "metaqs2-donut-chart", inputs: ["radius", "viewBox", "borderSize", "strokeWidth", "data"] }, { kind: "directive", type: ScrollMarkerDirective, selector: "[metaqs2ScrollMarker]" }] }); }
2659
2659
  }
2660
2660
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: QualityMatrixComponent, decorators: [{
2661
2661
  type: Component,
@@ -2690,8 +2690,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
2690
2690
  MatIconButton,
2691
2691
  DonutChartComponent,
2692
2692
  ScrollMarkerDirective,
2693
- ], template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title>\n Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{isLoading() ? \": Lade neue Daten.\" : \"\"}}</mat-card-title\n >\n </mat-card-header>\n <mat-card-content class=\"toolbar\">\n <metaqs2-qm-filter *ngFor=\"let filter of categoryControls.controls | keyvalue; trackBy: filterIdent\"\n [options]=\"categoryFilterValues.get(filter.key)\"\n [inputFormControl]=\"filter.value\"\n [label] = \"'filter.' + filter.key | translate\" />\n <div class=\"actionbar\">\n <mat-slide-toggle [disabled]=\"isLoading()\" labelPosition=\"before\" [formControl]=\"onlySourcesWithMaterial\" id=\"onlySourcesWithMaterial\">\n show only sources with material\n </mat-slide-toggle>\n <div style=\"flex: 1 1 auto\"></div>\n <metaqs2-datepicker *ngIf=\"showHistoricalData.value\" [disabled]=\"isLoading()\" [inputGroup]=\"range\" />\n <mat-slide-toggle [disabled]=\"isLoading()\" labelPosition=\"before\" [formControl]=\"showHistoricalData\" id=\"showHistoricalData\">\n show historical data\n </mat-slide-toggle>\n <button\n mat-icon-button\n color=\"primary\"\n [disabled]=\"isLoading\"\n (click)=\"refresh()\"\n matTooltip=\"Aktualisiere den IST-Stand\"\n matTooltipShowDelay=\"500\"\n >\n <mat-icon>refresh</mat-icon>\n </button>\n <div style=\"flex: 0 0 {{scroller.getBoundingClientRect().width}}px\"></div>\n <div class=\"scroll-controller\" #scroller> <!-- put the whole toolbar in a fixed container (MQS- -->\n <button mat-raised-button (click)=\"scrollToLeft()\" [disabled]=\"!isLeftScrollable()\" class=\"scroll-button\">\n <mat-icon style=\"margin: 0\">chevron_left</mat-icon>\n </button>\n <button mat-raised-button (click)=\"scrollToRight()\" [disabled]=\"!isRightScrollable()\" class=\"scroll-button\">\n <mat-icon style=\"margin: 0\">chevron_right</mat-icon>\n </button>\n </div>\n </div>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentQualityMatrix$.value.rows\" class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"row-header\" sticky>\n <th rowspan=\"2\" mat-header-cell *matHeaderCellDef #issueType>Issue Type</th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n matTooltip=\"{{row.meta.alt_label}}\"\n class=\"row-header mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{\"quality_matrix.\" + row.meta.label | translate }}\n </td>\n </ng-container>\n <!-- one column for the source -->\n <ng-container *ngFor=\"let col of filteredColumns; trackBy:columnIdent\" [matColumnDef]=\"col.id + '_source'\">\n <th [attr.colspan]=\"showHistoricalData.value?2:1\" metaqs2ScrollMarker mat-header-cell *matHeaderCellDef matTooltip=\"{{col.altLabel}}\">{{col.label}}</th>\n </ng-container>\n <!-- /source -->\n <!-- current Data Columns -->\n <ng-container *ngFor=\"let column of filteredColumns; trackBy:columnIdent\" [matColumnDef]=\"column.id + '_current'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"{{column.altLabel}}\">{{ range.controls.end.value?.toLocaleString(DateTime.DATE_SHORT) }} <br>({{column.total}})</th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\" #cell (mouseover)=\"showTooltip(row, column, cell)\" (mouseleave)=\"hideTooltip(cell)\">\n <a *ngIf=\"column.total > 0 else emptyDiv\" class=\"chart-container\" (click)=\"openEditLink( column.label, row.meta.label)\">\n <div>\n <metaqs2-donut-chart [data]=\"getDonutSlices(row, column)\" [borderSize]=\"25\"></metaqs2-donut-chart>\n </div>\n </a>\n <ng-template #emptyDiv>\n <div>-</div>\n </ng-template>\n </td>\n </ng-container>\n <!-- /current Data Columns -->\n <!-- past Data Columns -->\n <ng-container *ngIf=\"showHistoricalData.value\">\n <ng-container *ngFor=\"let column of filteredColumns; trackBy:columnIdent\" [matColumnDef]=\"column.id + '_past'\">\n <th class=\"historic-data-cell\" mat-header-cell\n *matHeaderCellDef>{{ range.controls.start.value?.toLocaleString(DateTime.DATE_SHORT) }}\n <br>{{ getPastColumn(column.id)?.total }}\n </th>\n <td class=\"historic-data-cell\" mat-cell *matCellDef=\"let row\">\n <ng-container *ngIf=\"getTrend(row, column) as trend\">\n <span [ngClass]=\"trend.trend\">\n <mat-icon aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" />\n {{ trend.delta }}\n </span>\n </ng-container>\n\n </td>\n </ng-container>\n </ng-container>\n <!-- /past Data Columns -->\n\n <!-- Generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['row-header'].concat( sourceColumns); sticky: true;\"></tr>\n <tr mat-header-row *matHeaderRowDef=\"allDataColumns; sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['row-header'].concat(allDataColumns)\"></tr>\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}mat-card-actions>mat-slide-toggle{margin-left:20px}.row{flex-grow:1;display:flex;align-items:center}table{width:100%;overflow-y:auto}table .scroll{flex-grow:1;overflow-y:auto}table th{vertical-align:top;padding:.375rem}table th:not(:last-child){border-right:1px solid #e4e4e4}table tr:first-child>th:first-child{text-align:left}table td:first-child{text-align:left}.cell{flex:1}.mat-mdc-cell{padding-top:5px}.mat-mdc-cell,.mat-mdc-header-cell{padding-left:5px;text-align:center}.mat-mdc-cell a.chart-container,.mat-mdc-header-cell a.chart-container{display:flex;justify-content:center}.mat-mdc-cell .trending_up,.mat-mdc-header-cell .trending_up{color:#4abeff}.mat-mdc-cell .trending_down,.mat-mdc-header-cell .trending_down{color:#c20808}.recent-data-cell,.mat-column-row-header{border-right:1px solid #e4e4e4}.mat-header-cell-label{color:#000;padding-left:30px;padding-right:30px;justify-content:left;border-bottom:1px solid #e4e4e4;font-style:normal;font-weight:500;font-size:110%;background:#ddf0fb;text-align:left}.mat-header-cell-label>div{display:flex;font-weight:700;font-style:normal;justify-content:left}.mat-header-cell-small{padding-left:5px;padding-right:5px;justify-content:left;font-style:normal;font-weight:400;font-size:105%;background:#ddf0fb;border-top:1px solid #e4e4e4;border-bottom:1px solid #e4e4e4}.mat-mdc-cell a{cursor:pointer;display:flex;align-items:center;justify-content:left}.mat-mdc-cell a>mat-icon{padding-right:5px;font-size:22px;height:20px;opacity:.75}.mat-mdc-cell a>mat-icon:hover,.mat-mdc-cell a>mat-icon:focus{text-decoration:none}.mat-mdc-cell .number{display:flex;height:47px;justify-content:left;align-items:center;padding-left:15px}.mat-mdc-cell .row-header{display:flex;height:47px;max-height:47px;justify-content:left;align-items:center;padding-left:15px}.mat-mdc-cell .row-header-sum{display:flex;height:47px;max-height:47px;justify-content:left;align-items:center;border-right:5px solid #bdbdbd}.mat-mdc-card{width:100%;box-shadow:none}.mat-mdc-card ::ng-deep mat-card-header{align-items:center}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text{flex-grow:1;margin:0}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text mat-card-title{padding-top:20px;font-size:120%}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text mat-card-title .count{font-size:80%;color:#888}.mat-mdc-card .source-header{font-style:normal;font-weight:400;font-size:20px;height:30px;width:60%}.mat-mdc-card .source-header .robot-explanation{font-size:15px}.mat-mdc-card .scroll{flex-grow:1;overflow-y:auto}.mat-header-cell-scope{color:#545454}.mat-mdc-header-row{height:70px;max-height:70px;min-height:56px}:host{overflow:auto}:host ::ng-deep thead{border:10px solid #ff0000;position:relative;z-index:1}.mat-cell-level-1{padding-left:20px!important}.mat-cell-level-2{padding-left:40px!important}.mat-cell-level-3{padding-left:60px!important}.mat-cell-level-4{padding-left:80px!important}.mat-cell-level-5{padding-left:100px!important}.mat-cell-level-6{padding-left:120px!important}.mat-cell-level-7{padding-left:140px!important}.mat-cell-level-8{padding-left:160px!important}.actionbar{flex:1 1 auto;display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:.5rem}.scroll-controller{position:fixed;right:.5rem;z-index:100;display:flex;flex-direction:row;justify-content:space-between;align-items:center;gap:.5rem}.scroll-button{min-width:0;padding-left:.25rem;padding-right:.25rem;text-align:center;height:1.75rem}.toolbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:stretch;gap:.5rem}\n"] }]
2694
- }], ctorParameters: () => [{ type: MetaApiService }, { type: EditorialLinkService }, { type: i1$3.Overlay }, { type: TooltipService }], propDecorators: { issueTypeHeader: [{
2693
+ ], template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title>Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{isLoading() ? \": Lade neue Daten.\" : \"\"}}</mat-card-title>\n </mat-card-header>\n <mat-card-content class=\"toolbar\">\n <metaqs2-qm-filter *ngFor=\"let filter of categoryControls.controls | keyvalue; trackBy: filterIdent\"\n [options]=\"categoryFilterValues.get(filter.key)\"\n [inputFormControl]=\"filter.value\"\n [label] = \"'filter.' + filter.key | translate\" />\n <div class=\"actionbar\">\n <mat-slide-toggle [disabled]=\"isLoading()\" labelPosition=\"before\" [formControl]=\"isOnlySourcesWithMaterialEnabledFormField\" id=\"onlySourcesWithMaterial\">\n show only sources with material\n </mat-slide-toggle>\n <div style=\"flex: 1 1 auto\"></div>\n <metaqs2-datepicker *ngIf=\"isHistoricalDataEnabled()\" [disabled]=\"isLoading()\" [inputGroup]=\"range\" />\n <mat-slide-toggle [disabled]=\"isLoading()\" labelPosition=\"before\" [formControl]=\"isHistoricalDataEnabledFormField\" id=\"showHistoricalData\">\n show historical data\n </mat-slide-toggle>\n <button\n mat-icon-button\n color=\"primary\"\n [disabled]=\"isLoading()\"\n (click)=\"refresh()\"\n matTooltip=\"Aktualisiere den IST-Stand\"\n matTooltipShowDelay=\"500\"\n >\n <mat-icon>refresh</mat-icon>\n </button>\n <div style=\"flex: 0 0 {{scroller.getBoundingClientRect().width}}px\"></div>\n <div class=\"scroll-controller\" #scroller> <!-- put the whole toolbar in a fixed container (MQS- -->\n <button mat-raised-button (click)=\"scrollToLeft()\" [disabled]=\"!isLeftScrollable()\" class=\"scroll-button\">\n <mat-icon style=\"margin: 0\">chevron_left</mat-icon>\n </button>\n <button mat-raised-button (click)=\"scrollToRight()\" [disabled]=\"!isRightScrollable()\" class=\"scroll-button\">\n <mat-icon style=\"margin: 0\">chevron_right</mat-icon>\n </button>\n </div>\n </div>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentQualityMatrix().rows\" class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"row-header\" sticky>\n <th rowspan=\"2\" mat-header-cell *matHeaderCellDef #issueType>Issue Type</th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n matTooltip=\"{{row.meta.alt_label}}\"\n class=\"row-header mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{\"quality_matrix.\" + row.meta.label | translate }}\n </td>\n </ng-container>\n <!-- one column for the source -->\n <ng-container *ngFor=\"let col of filteredColumns(); trackBy:columnIdent\" [matColumnDef]=\"col.id + '_source'\">\n <th [attr.colspan]=\"isHistoricalDataEnabled() ? 2 : 1\" metaqs2ScrollMarker mat-header-cell *matHeaderCellDef matTooltip=\"{{col.altLabel}}\">{{col.label}}</th>\n </ng-container>\n <!-- /source -->\n <!-- current Data Columns -->\n <ng-container *ngFor=\"let column of filteredColumns(); trackBy:columnIdent\" [matColumnDef]=\"column.id + '_current'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"{{column.altLabel}}\">{{ range.controls.end.value?.toLocaleString(DateTime.DATE_SHORT) }} <br>({{column.total}})</th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\" #cell (mouseover)=\"showTooltip(row, column, cell)\" (mouseleave)=\"hideTooltip(cell)\">\n <a *ngIf=\"column.total > 0 else emptyDiv\" class=\"chart-container\" (click)=\"openEditLink( column.label, row.meta.label)\">\n <div>\n <metaqs2-donut-chart [data]=\"getDonutSlices(row, column)\" [borderSize]=\"25\"></metaqs2-donut-chart>\n </div>\n </a>\n <ng-template #emptyDiv>\n <div>-</div>\n </ng-template>\n </td>\n </ng-container>\n <!-- /current Data Columns -->\n <!-- past Data Columns -->\n <ng-container *ngIf=\"isHistoricalDataEnabled()\">\n <ng-container *ngFor=\"let column of filteredColumns(); trackBy:columnIdent\" [matColumnDef]=\"column.id + '_past'\">\n <th class=\"historic-data-cell\" mat-header-cell\n *matHeaderCellDef>{{ range.controls.start.value?.toLocaleString(DateTime.DATE_SHORT) }}\n <br>{{ getPastColumn(column.id)?.total }}\n </th>\n <td class=\"historic-data-cell\" mat-cell *matCellDef=\"let row\">\n <ng-container *ngIf=\"getTrend(row, column) as trend\">\n <span [ngClass]=\"trend.trend\">\n <mat-icon aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" />\n {{ trend.delta }}\n </span>\n </ng-container>\n\n </td>\n </ng-container>\n </ng-container>\n <!-- /past Data Columns -->\n\n <!-- Generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['row-header'].concat(sourceColumns()); sticky: true;\"></tr>\n <tr mat-header-row *matHeaderRowDef=\"allDataColumns(); sticky: true;\" [hidden]=\"!isHistoricalDataEnabled()\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['row-header'].concat(allDataColumns())\"></tr>\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}mat-card-actions>mat-slide-toggle{margin-left:20px}.row{flex-grow:1;display:flex;align-items:center}table{width:100%;overflow-y:auto}table .scroll{flex-grow:1;overflow-y:auto}table th{vertical-align:top;padding:.375rem}table th:not(:last-child){border-right:1px solid #e4e4e4}table tr:first-child>th:first-child{text-align:left}table td:first-child{text-align:left}.cell{flex:1}.mat-mdc-cell{padding-top:5px}.mat-mdc-cell,.mat-mdc-header-cell{padding-left:5px;text-align:center}.mat-mdc-cell a.chart-container,.mat-mdc-header-cell a.chart-container{display:flex;justify-content:center}.mat-mdc-cell .trending_up,.mat-mdc-header-cell .trending_up{color:#4abeff}.mat-mdc-cell .trending_down,.mat-mdc-header-cell .trending_down{color:#c20808}.recent-data-cell,.mat-column-row-header{border-right:1px solid #e4e4e4}.mat-header-cell-label{color:#000;padding-left:30px;padding-right:30px;justify-content:left;border-bottom:1px solid #e4e4e4;font-style:normal;font-weight:500;font-size:110%;background:#ddf0fb;text-align:left}.mat-header-cell-label>div{display:flex;font-weight:700;font-style:normal;justify-content:left}.mat-header-cell-small{padding-left:5px;padding-right:5px;justify-content:left;font-style:normal;font-weight:400;font-size:105%;background:#ddf0fb;border-top:1px solid #e4e4e4;border-bottom:1px solid #e4e4e4}.mat-mdc-cell a{cursor:pointer;display:flex;align-items:center;justify-content:left}.mat-mdc-cell a>mat-icon{padding-right:5px;font-size:22px;height:20px;opacity:.75}.mat-mdc-cell a>mat-icon:hover,.mat-mdc-cell a>mat-icon:focus{text-decoration:none}.mat-mdc-cell .number{display:flex;height:47px;justify-content:left;align-items:center;padding-left:15px}.mat-mdc-cell .row-header{display:flex;height:47px;max-height:47px;justify-content:left;align-items:center;padding-left:15px}.mat-mdc-cell .row-header-sum{display:flex;height:47px;max-height:47px;justify-content:left;align-items:center;border-right:5px solid #bdbdbd}.mat-mdc-card{width:100%;box-shadow:none}.mat-mdc-card ::ng-deep mat-card-header{align-items:center}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text{flex-grow:1;margin:0}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text mat-card-title{padding-top:20px;font-size:120%}.mat-mdc-card ::ng-deep mat-card-header .mat-card-header-text mat-card-title .count{font-size:80%;color:#888}.mat-mdc-card .source-header{font-style:normal;font-weight:400;font-size:20px;height:30px;width:60%}.mat-mdc-card .source-header .robot-explanation{font-size:15px}.mat-mdc-card .scroll{flex-grow:1;overflow-y:auto}.mat-header-cell-scope{color:#545454}.mat-mdc-header-row{height:70px;max-height:70px;min-height:56px}:host{overflow:auto}:host ::ng-deep thead{border:10px solid #ff0000;position:relative;z-index:1}.mat-cell-level-1{padding-left:20px!important}.mat-cell-level-2{padding-left:40px!important}.mat-cell-level-3{padding-left:60px!important}.mat-cell-level-4{padding-left:80px!important}.mat-cell-level-5{padding-left:100px!important}.mat-cell-level-6{padding-left:120px!important}.mat-cell-level-7{padding-left:140px!important}.mat-cell-level-8{padding-left:160px!important}.actionbar{flex:1 1 auto;display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:.5rem}.scroll-controller{position:fixed;right:.5rem;z-index:100;display:flex;flex-direction:row;justify-content:space-between;align-items:center;gap:.5rem}.scroll-button{min-width:0;padding-left:.25rem;padding-right:.25rem;text-align:center;height:1.75rem}.toolbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:stretch;gap:.5rem}\n"] }]
2694
+ }], propDecorators: { issueTypeHeader: [{
2695
2695
  type: ViewChild,
2696
2696
  args: ['issueType', {
2697
2697
  read: ElementRef,
@@ -3140,7 +3140,7 @@ class TreeCollectionDetailsComponent {
3140
3140
  return this.linkService.openByCollectionAndIssueType(collectionId, issueType, title);
3141
3141
  }
3142
3142
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeCollectionDetailsComponent, deps: [{ token: MetaApiService }, { token: i2$3.TranslateService }, { token: EditorialLinkService }], target: i0.ɵɵFactoryTarget.Component }); }
3143
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TreeCollectionDetailsComponent, isStandalone: true, selector: "metaqs2-tree-collection-details", inputs: { collectionId: "collectionId", pageTitle: "pageTitle" }, ngImport: i0, template: "<mat-card>\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title>\n Qualit\u00E4tsmetrik: {{pageTitle | translate}}{{isLoading() ? \": Lade neue Daten.\" : \"\"}}</mat-card-title\n >\n </mat-card-header>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table *ngIf=\"!isLoading()\" [ngClass]=\"{'while-loading': isLoading()}\" mat-table [dataSource]=\"recentQualityMatrix$.value.rows\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"row-header\" sticky>\n <th mat-header-cell *matHeaderCellDef>Sammlung</th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n class=\"row-header {{'mat-cell-level-' + (row.meta.level+1)}}\"\n >\n <a (click)=\"openCollection(row.meta.id)\">\n <mat-icon [svgIcon]=\"'level-' + Math.min(3, row.meta.level+1)\"></mat-icon>\n {{row.meta.label}}\n </a>\n </td>\n </ng-container>\n\n <!-- Data Columns -->\n <ng-container *ngFor=\"let column of dataColumns\" [matColumnDef]=\"column.id\">\n <th mat-header-cell *matHeaderCellDef>{{ \"quality_matrix.\" + column.label | translate }}</th>\n <td mat-cell *matCellDef=\"let row\">\n <ng-container *ngIf=\" column.id === 'collection_issues' else countsWithLinks\">\n {{ translateCollectionIssues(row.counts[column.id]) | async }}\n </ng-container>\n <ng-template #countsWithLinks>\n <a *ngIf=\"row.counts[column.id]\" (click)=\"showMaterialWithIssue(row.meta.id, row.meta.label, column.id)\">\n {{ row.counts[column.id] }}\n </a>\n </ng-template>\n\n\n </td>\n </ng-container>\n\n <!-- Generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['row-header'].concat(columnIds); sticky:true\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['row-header'].concat(columnIds)\"></tr>\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}tr:nth-child(2n){background-color:#e4e4e4}tr:nth-child(2n)>.mat-column-row-header,tr:nth-child(2n) .mat-mdc-cell{border-right-color:#fff}.mat-mdc-cell,.mat-mdc-header-cell,.mat-column-row-header{border-right:1px solid #e4e4e4}.mat-mdc-cell mat-icon,.mat-mdc-header-cell mat-icon,.mat-column-row-header mat-icon{color:var(--mat-table-row-item-label-text-color);height:16px;padding-right:5px;font-size:16px}.mat-mdc-header-cell,.mat-mdc-cell{padding-left:5px;text-align:left}.mat-mdc-header-cell a,.mat-mdc-cell a{cursor:pointer;text-decoration:underline}.mat-mdc-header-cell a:hover,.mat-mdc-cell a:hover{text-decoration:underline}.row-header a{text-decoration:none;align-items:center;display:flex}.mat-column-totals_collection.noMaterial{background-color:#fad6da}.mat-column-totals_collection.fewMaterials{background-color:#fff1d6}.mat-cell-level-1{padding-left:20px!important;text-align:left}.mat-cell-level-2{padding-left:40px!important;text-align:left}.mat-cell-level-3{padding-left:60px!important;text-align:left}.mat-cell-level-4{padding-left:80px!important;text-align:left}.mat-cell-level-5{padding-left:100px!important;text-align:left}.mat-cell-level-6{padding-left:120px!important;text-align:left}.mat-cell-level-7{padding-left:140px!important;text-align:left}.mat-cell-level-8{padding-left:160px!important;text-align:left}mat-spinner{flex-grow:1;display:flex;align-self:center;justify-self:center;margin-top:20px}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$3.TranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "component", type: i3$1.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i3$1.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i4.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: ProgressSpinnerComponent, selector: "metaqs2-progress-spinner", inputs: ["color", "diameter", "strokeWidth", "backdropEnabled", "positionGloballyCenter", "displayProgressSpinner"] }] }); }
3143
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TreeCollectionDetailsComponent, isStandalone: true, selector: "metaqs2-tree-collection-details", inputs: { collectionId: "collectionId", pageTitle: "pageTitle" }, ngImport: i0, template: "<mat-card>\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title>\n Qualit\u00E4tsmetrik: {{pageTitle | translate}}{{isLoading() ? \": Lade neue Daten.\" : \"\"}}</mat-card-title\n >\n </mat-card-header>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table *ngIf=\"!isLoading()\" [ngClass]=\"{'while-loading': isLoading()}\" mat-table [dataSource]=\"recentQualityMatrix$.value.rows\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"row-header\" sticky>\n <th mat-header-cell *matHeaderCellDef>Sammlung</th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n class=\"row-header {{'mat-cell-level-' + (row.meta.level+1)}}\"\n >\n <a (click)=\"openCollection(row.meta.id)\">\n <mat-icon [svgIcon]=\"'level-' + Math.min(3, row.meta.level+1)\"></mat-icon>\n {{row.meta.label}}\n </a>\n </td>\n </ng-container>\n\n <!-- Data Columns -->\n <ng-container *ngFor=\"let column of dataColumns\" [matColumnDef]=\"column.id\">\n <th mat-header-cell *matHeaderCellDef>{{ \"quality_matrix.\" + column.label | translate }}</th>\n <td mat-cell *matCellDef=\"let row\">\n <ng-container *ngIf=\" column.id === 'collection_issues' else countsWithLinks\">\n {{ translateCollectionIssues(row.counts[column.id]) | async }}\n </ng-container>\n <ng-template #countsWithLinks>\n <a *ngIf=\"row.counts[column.id]\" (click)=\"showMaterialWithIssue(row.meta.id, row.meta.label, column.id)\">\n {{ row.counts[column.id] }}\n </a>\n </ng-template>\n\n\n </td>\n </ng-container>\n\n <!-- Generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['row-header'].concat(columnIds); sticky:true\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['row-header'].concat(columnIds)\"></tr>\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}tr:nth-child(2n){background-color:#e4e4e4}tr:nth-child(2n)>.mat-column-row-header,tr:nth-child(2n) .mat-mdc-cell{border-right-color:#fff}.mat-mdc-cell,.mat-mdc-header-cell,.mat-column-row-header{border-right:1px solid #e4e4e4}.mat-mdc-cell mat-icon,.mat-mdc-header-cell mat-icon,.mat-column-row-header mat-icon{color:var(--mat-table-row-item-label-text-color);height:16px;padding-right:5px;font-size:16px}.mat-mdc-header-cell,.mat-mdc-cell{padding-left:5px;text-align:left}.mat-mdc-header-cell a,.mat-mdc-cell a{cursor:pointer;text-decoration:underline}.mat-mdc-header-cell a:hover,.mat-mdc-cell a:hover{text-decoration:underline}.row-header a{text-decoration:none;align-items:center;display:flex}.mat-column-totals_collection.noMaterial{background-color:#fad6da}.mat-column-totals_collection.fewMaterials{background-color:#fff1d6}.mat-cell-level-1{padding-left:20px!important;text-align:left}.mat-cell-level-2{padding-left:40px!important;text-align:left}.mat-cell-level-3{padding-left:60px!important;text-align:left}.mat-cell-level-4{padding-left:80px!important;text-align:left}.mat-cell-level-5{padding-left:100px!important;text-align:left}.mat-cell-level-6{padding-left:120px!important;text-align:left}.mat-cell-level-7{padding-left:140px!important;text-align:left}.mat-cell-level-8{padding-left:160px!important;text-align:left}mat-spinner{flex-grow:1;display:flex;align-self:center;justify-self:center;margin-top:20px}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$3.TranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "component", type: i3$1.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i3$1.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i5$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i5$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i5$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i5$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i5$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i5$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i5$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i5$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i5$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i5$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: ProgressSpinnerComponent, selector: "metaqs2-progress-spinner", inputs: ["color", "diameter", "strokeWidth", "backdropEnabled", "positionGloballyCenter", "displayProgressSpinner"] }] }); }
3144
3144
  }
3145
3145
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeCollectionDetailsComponent, decorators: [{
3146
3146
  type: Component,
@@ -3428,7 +3428,7 @@ class TreeSearchCountsComponent {
3428
3428
  return this.collectionColumns.flatMap((e, i) => [e, this.searchColumns[i]]);
3429
3429
  }
3430
3430
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeSearchCountsComponent, deps: [{ token: MetaApiService }, { token: ConfigHelperService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); }
3431
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TreeSearchCountsComponent, isStandalone: true, selector: "metaqs2-tree-search-counts", inputs: { pageTitle: "pageTitle", collectionId: "collectionId" }, ngImport: i0, template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title>Material in Sammlungen{{isLoading() ? \": Lade neue Daten.\" : \"\"}}</mat-card-title>\n </mat-card-header>\n <mat-card-content class=\"toolbar\">\n <div style=\"flex: 1 1 auto;\"></div>\n <div class=\"actionbar\">\n <mat-slide-toggle labelPosition=\"before\" class=\"toggle\" [formControl]=\"showOERonly\">\n zeige nur OER\n </mat-slide-toggle>\n <mat-slide-toggle labelPosition=\"before\" class=\"toggle\" [formControl]=\"showAllColumns\">\n zeige alle Typen\n </mat-slide-toggle>\n </div>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table *ngIf=\"columns\" [ngClass]=\"{'while-loading': isLoading()}\" mat-table [dataSource]=\"materialCounts.rows\" class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Label Column -->\n <ng-container matColumnDef=\"label-col\" sticky>\n <th rowspan=\"2\" mat-header-cell *matHeaderCellDef>Sammlung</th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n class=\"label-col {{'mat-cell-level-' + (row.meta.level+1)}}\"\n >\n <a (click)=\"openCollection(row.meta.id)\">\n <mat-icon [svgIcon]=\"'level-' + Math.min(3, row.meta.level+1)\"></mat-icon>\n {{ row.meta.label }}\n </a>\n </td>\n </ng-container>\n <!-- one column for the MaterialType spanning the collection and search columns-->\n <ng-container *ngFor=\"let col of filteredColumns; trackBy:columnIdent\" [matColumnDef]=\"col.id + '_type'\">\n <th [attr.colspan]=\"2\" mat-header-cell *matHeaderCellDef class=\"mat-cell-level-{{col.level}}\">{{col.label}}</th>\n </ng-container>\n <!-- /source -->\n <!-- collection Data Columns -->\n <ng-container *ngFor=\"let column of filteredColumns; trackBy:columnIdent\" [matColumnDef]=\"column.id + COLLECTION_POSTFIX\">\n <th mat-header-cell *matHeaderCellDef>in Sammlung</th>\n <td [class.noMaterial]=\"!row.counts[column.id]?.sufficient || row.counts[column.id]?.sufficient <= 1\"\n [class.fewMaterials]=\"1 < row.counts[column.id]?.sufficient && row.counts[column.id]?.sufficient <= 3\"\n class=\"collection-data-cell\"\n mat-cell *matCellDef=\"let row\">\n <a (click)=\"showCollectionItems(row.meta.id, row.meta.label, column.id)\">\n {{ row.counts[column.id]?.sufficient || '0' }}\n </a>\n </td>\n </ng-container>\n <!-- /collection Data Columns -->\n <!-- search Data Columns -->\n <ng-container *ngFor=\"let column of filteredColumns let index = index; trackBy:columnIdent\" [matColumnDef]=\"column.id + SEARCH_POSTFIX\">\n <th mat-header-cell *matHeaderCellDef>Suche</th>\n <td class=\"search-data-cell\" mat-cell *matCellDef=\"let row\">\n <a (click)=\"searchInEditor(column.id, row.meta.label)\">\n <ng-container *ngIf=\"(( searchCounts | async)?.has(column.id + '_' + row.meta.id) ) else zeroOrLoading\">\n {{ (searchCounts | async)?.get(column.id + '_' + row.meta.id) }}\n </ng-container>\n <ng-template #zeroOrLoading>\n <ng-container *ngIf=\"rowsLoaded.has(row.meta.id) else loadingBlock\"> 0 </ng-container>\n </ng-template>\n <ng-template #loadingBlock>\n loading\u2026\n </ng-template>\n </a>\n </td>\n </ng-container>\n <!-- /search Data Columns -->\n <!-- Generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['label-col'].concat( typeColumns ); sticky: true;\"></tr>\n <tr mat-header-row *matHeaderRowDef=\"alternatingDataColumns; sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['label-col'].concat(alternatingDataColumns)\"></tr>\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}tr:nth-child(2n){background-color:#e4e4e4}tr:nth-child(2n)>.mat-column-label-col,tr:nth-child(2n) .search-data-cell{border-right-color:#fff}.search-data-cell,.mat-mdc-header-cell,.mat-column-label-col{border-right:1px solid #e4e4e4}.search-data-cell mat-icon,.mat-mdc-header-cell mat-icon,.mat-column-label-col mat-icon{color:var(--mat-table-row-item-label-text-color);height:16px;padding-right:5px;font-size:16px}.mat-mdc-header-cell,.mat-mdc-cell{padding-left:5px;text-align:center}.mat-mdc-header-cell a,.mat-mdc-cell a{cursor:pointer;text-decoration:underline}.mat-mdc-header-cell a:hover,.mat-mdc-cell a:hover{text-decoration:underline}.label-col a{text-decoration:none;align-items:center;display:flex}.mat-column-totals_collection.noMaterial{background-color:#fad6da}.mat-column-totals_collection.fewMaterials{background-color:#fff1d6}.mat-cell-level-1{padding-left:20px!important;text-align:left}.mat-cell-level-2{padding-left:40px!important;text-align:left}.mat-cell-level-3{padding-left:60px!important;text-align:left}.mat-cell-level-4{padding-left:80px!important;text-align:left}.mat-cell-level-5{padding-left:100px!important;text-align:left}.mat-cell-level-6{padding-left:120px!important;text-align:left}.mat-cell-level-7{padding-left:140px!important;text-align:left}.mat-cell-level-8{padding-left:160px!important;text-align:left}.toolbar,.actionbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:stretch;gap:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$1.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i3$1.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i3$1.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i4.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ProgressSpinnerComponent, selector: "metaqs2-progress-spinner", inputs: ["color", "diameter", "strokeWidth", "backdropEnabled", "positionGloballyCenter", "displayProgressSpinner"] }] }); }
3431
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TreeSearchCountsComponent, isStandalone: true, selector: "metaqs2-tree-search-counts", inputs: { pageTitle: "pageTitle", collectionId: "collectionId" }, ngImport: i0, template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title>Material in Sammlungen{{isLoading() ? \": Lade neue Daten.\" : \"\"}}</mat-card-title>\n </mat-card-header>\n <mat-card-content class=\"toolbar\">\n <div style=\"flex: 1 1 auto;\"></div>\n <div class=\"actionbar\">\n <mat-slide-toggle labelPosition=\"before\" class=\"toggle\" [formControl]=\"showOERonly\">\n zeige nur OER\n </mat-slide-toggle>\n <mat-slide-toggle labelPosition=\"before\" class=\"toggle\" [formControl]=\"showAllColumns\">\n zeige alle Typen\n </mat-slide-toggle>\n </div>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table *ngIf=\"columns\" [ngClass]=\"{'while-loading': isLoading()}\" mat-table [dataSource]=\"materialCounts.rows\" class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Label Column -->\n <ng-container matColumnDef=\"label-col\" sticky>\n <th rowspan=\"2\" mat-header-cell *matHeaderCellDef>Sammlung</th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n class=\"label-col {{'mat-cell-level-' + (row.meta.level+1)}}\"\n >\n <a (click)=\"openCollection(row.meta.id)\">\n <mat-icon [svgIcon]=\"'level-' + Math.min(3, row.meta.level+1)\"></mat-icon>\n {{ row.meta.label }}\n </a>\n </td>\n </ng-container>\n <!-- one column for the MaterialType spanning the collection and search columns-->\n <ng-container *ngFor=\"let col of filteredColumns; trackBy:columnIdent\" [matColumnDef]=\"col.id + '_type'\">\n <th [attr.colspan]=\"2\" mat-header-cell *matHeaderCellDef class=\"mat-cell-level-{{col.level}}\">{{col.label}}</th>\n </ng-container>\n <!-- /source -->\n <!-- collection Data Columns -->\n <ng-container *ngFor=\"let column of filteredColumns; trackBy:columnIdent\" [matColumnDef]=\"column.id + COLLECTION_POSTFIX\">\n <th mat-header-cell *matHeaderCellDef>in Sammlung</th>\n <td [class.noMaterial]=\"!row.counts[column.id]?.sufficient || row.counts[column.id]?.sufficient <= 1\"\n [class.fewMaterials]=\"1 < row.counts[column.id]?.sufficient && row.counts[column.id]?.sufficient <= 3\"\n class=\"collection-data-cell\"\n mat-cell *matCellDef=\"let row\">\n <a (click)=\"showCollectionItems(row.meta.id, row.meta.label, column.id)\">\n {{ row.counts[column.id]?.sufficient || '0' }}\n </a>\n </td>\n </ng-container>\n <!-- /collection Data Columns -->\n <!-- search Data Columns -->\n <ng-container *ngFor=\"let column of filteredColumns let index = index; trackBy:columnIdent\" [matColumnDef]=\"column.id + SEARCH_POSTFIX\">\n <th mat-header-cell *matHeaderCellDef>Suche</th>\n <td class=\"search-data-cell\" mat-cell *matCellDef=\"let row\">\n <a (click)=\"searchInEditor(column.id, row.meta.label)\">\n <ng-container *ngIf=\"(( searchCounts | async)?.has(column.id + '_' + row.meta.id) ) else zeroOrLoading\">\n {{ (searchCounts | async)?.get(column.id + '_' + row.meta.id) }}\n </ng-container>\n <ng-template #zeroOrLoading>\n <ng-container *ngIf=\"rowsLoaded.has(row.meta.id) else loadingBlock\"> 0 </ng-container>\n </ng-template>\n <ng-template #loadingBlock>\n loading\u2026\n </ng-template>\n </a>\n </td>\n </ng-container>\n <!-- /search Data Columns -->\n <!-- Generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['label-col'].concat( typeColumns ); sticky: true;\"></tr>\n <tr mat-header-row *matHeaderRowDef=\"alternatingDataColumns; sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['label-col'].concat(alternatingDataColumns)\"></tr>\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}tr:nth-child(2n){background-color:#e4e4e4}tr:nth-child(2n)>.mat-column-label-col,tr:nth-child(2n) .search-data-cell{border-right-color:#fff}.search-data-cell,.mat-mdc-header-cell,.mat-column-label-col{border-right:1px solid #e4e4e4}.search-data-cell mat-icon,.mat-mdc-header-cell mat-icon,.mat-column-label-col mat-icon{color:var(--mat-table-row-item-label-text-color);height:16px;padding-right:5px;font-size:16px}.mat-mdc-header-cell,.mat-mdc-cell{padding-left:5px;text-align:center}.mat-mdc-header-cell a,.mat-mdc-cell a{cursor:pointer;text-decoration:underline}.mat-mdc-header-cell a:hover,.mat-mdc-cell a:hover{text-decoration:underline}.label-col a{text-decoration:none;align-items:center;display:flex}.mat-column-totals_collection.noMaterial{background-color:#fad6da}.mat-column-totals_collection.fewMaterials{background-color:#fff1d6}.mat-cell-level-1{padding-left:20px!important;text-align:left}.mat-cell-level-2{padding-left:40px!important;text-align:left}.mat-cell-level-3{padding-left:60px!important;text-align:left}.mat-cell-level-4{padding-left:80px!important;text-align:left}.mat-cell-level-5{padding-left:100px!important;text-align:left}.mat-cell-level-6{padding-left:120px!important;text-align:left}.mat-cell-level-7{padding-left:140px!important;text-align:left}.mat-cell-level-8{padding-left:160px!important;text-align:left}.toolbar,.actionbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:stretch;gap:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$1.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i3$1.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i3$1.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i5$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i5$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i5$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i5$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i5$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i5$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i5$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i5$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i5$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i5$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ProgressSpinnerComponent, selector: "metaqs2-progress-spinner", inputs: ["color", "diameter", "strokeWidth", "backdropEnabled", "positionGloballyCenter", "displayProgressSpinner"] }] }); }
3432
3432
  }
3433
3433
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeSearchCountsComponent, decorators: [{
3434
3434
  type: Component,
@@ -3512,7 +3512,7 @@ class MonthpickerComponent {
3512
3512
  { provide: LOCALE_ID, useValue: 'de-DE' },
3513
3513
  { provide: MAT_DATE_LOCALE, useValue: 'de-DE' },
3514
3514
  { provide: MAT_LUXON_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true, firstDayOfWeek: 1 } },
3515
- ], viewQueries: [{ propertyName: "start", first: true, predicate: ["start"], descendants: true, read: ElementRef, static: true }, { propertyName: "ripple", first: true, predicate: ["ripple"], descendants: true, read: MatRipple, static: true }], ngImport: i0, template: "<!--\n<mat-card>\n <mat-card-header>\n <mat-card-title> Monatlicher Vergleich </mat-card-title>\n </mat-card-header>\n <mat-card-content [formGroup]=\"inputGroup\">\n </!-- start date --/>\n -->\n<div [formGroup]=\"inputGroup\" matRipple #ripple=\"matRipple\" [matRippleDisabled]=\"true\">\n <mat-form-field>\n <mat-label>Zeitpunkt 1</mat-label>\n <input matInput\n #start\n [disabled]=\"disabled\"\n [min]=\"inputGroup.controls.start.defaultValue\"\n [max]=\"inputGroup.controls.end.defaultValue\"\n [matDatepicker]=\"picker1\" formControlName=\"start\"\n placeholder=\"Starts date\"\n >\n <mat-datepicker-toggle matIconSuffix [for]=\"picker1\"></mat-datepicker-toggle>\n <mat-datepicker\n [disabled]=\"disabled\"\n #picker1\n [startAt]=\"inputGroup.controls.start.defaultValue\"\n [startView]=\"startView\"\n (monthSelected)=\"setStart($event, picker1)\"\n\n >\n </mat-datepicker>\n </mat-form-field>\n <!-- /start date -->\n <!-- end date -->\n <mat-form-field>\n <mat-label>Zeitpunkt2</mat-label>\n <input matInput\n [disabled]=\"disabled\"\n [min]=\"inputGroup.controls.start.defaultValue\"\n [max]=\"inputGroup.controls.end.defaultValue\"\n [matDatepicker]=\"picker2\"\n formControlName=\"end\"\n placeholder=\"End date\"\n >\n <mat-datepicker-toggle matIconSuffix [for]=\"picker2\"></mat-datepicker-toggle>\n <mat-datepicker\n [disabled]=\"disabled\"\n #picker2\n [startAt]=\"inputGroup.controls.end.value\"\n [startView]=\"startView\"\n (monthSelected)=\"setEnd($event, picker2)\"\n >\n </mat-datepicker>\n </mat-form-field>\n <!-- /end date -->\n</div>\n<!--\n </mat-card-content>\n</mat-card>\n-->\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }] }); }
3515
+ ], viewQueries: [{ propertyName: "start", first: true, predicate: ["start"], descendants: true, read: (ElementRef), static: true }, { propertyName: "ripple", first: true, predicate: ["ripple"], descendants: true, read: MatRipple, static: true }], ngImport: i0, template: "<!--\n<mat-card>\n <mat-card-header>\n <mat-card-title> Monatlicher Vergleich </mat-card-title>\n </mat-card-header>\n <mat-card-content [formGroup]=\"inputGroup\">\n </!-- start date --/>\n -->\n<div [formGroup]=\"inputGroup\" matRipple #ripple=\"matRipple\" [matRippleDisabled]=\"true\">\n <mat-form-field>\n <mat-label>Zeitpunkt 1</mat-label>\n <input matInput\n #start\n [disabled]=\"disabled\"\n [min]=\"inputGroup.controls.start.defaultValue\"\n [max]=\"inputGroup.controls.end.defaultValue\"\n [matDatepicker]=\"picker1\" formControlName=\"start\"\n placeholder=\"Starts date\"\n >\n <mat-datepicker-toggle matIconSuffix [for]=\"picker1\"></mat-datepicker-toggle>\n <mat-datepicker\n [disabled]=\"disabled\"\n #picker1\n [startAt]=\"inputGroup.controls.start.defaultValue\"\n [startView]=\"startView\"\n (monthSelected)=\"setStart($event, picker1)\"\n\n >\n </mat-datepicker>\n </mat-form-field>\n <!-- /start date -->\n <!-- end date -->\n <mat-form-field>\n <mat-label>Zeitpunkt2</mat-label>\n <input matInput\n [disabled]=\"disabled\"\n [min]=\"inputGroup.controls.start.defaultValue\"\n [max]=\"inputGroup.controls.end.defaultValue\"\n [matDatepicker]=\"picker2\"\n formControlName=\"end\"\n placeholder=\"End date\"\n >\n <mat-datepicker-toggle matIconSuffix [for]=\"picker2\"></mat-datepicker-toggle>\n <mat-datepicker\n [disabled]=\"disabled\"\n #picker2\n [startAt]=\"inputGroup.controls.end.value\"\n [startView]=\"startView\"\n (monthSelected)=\"setEnd($event, picker2)\"\n >\n </mat-datepicker>\n </mat-form-field>\n <!-- /end date -->\n</div>\n<!--\n </mat-card-content>\n</mat-card>\n-->\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }] }); }
3516
3516
  }
3517
3517
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MonthpickerComponent, decorators: [{
3518
3518
  type: Component,
@@ -3539,7 +3539,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3539
3539
  { provide: MAT_DATE_LOCALE, useValue: 'de-DE' },
3540
3540
  { provide: MAT_LUXON_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true, firstDayOfWeek: 1 } },
3541
3541
  ], template: "<!--\n<mat-card>\n <mat-card-header>\n <mat-card-title> Monatlicher Vergleich </mat-card-title>\n </mat-card-header>\n <mat-card-content [formGroup]=\"inputGroup\">\n </!-- start date --/>\n -->\n<div [formGroup]=\"inputGroup\" matRipple #ripple=\"matRipple\" [matRippleDisabled]=\"true\">\n <mat-form-field>\n <mat-label>Zeitpunkt 1</mat-label>\n <input matInput\n #start\n [disabled]=\"disabled\"\n [min]=\"inputGroup.controls.start.defaultValue\"\n [max]=\"inputGroup.controls.end.defaultValue\"\n [matDatepicker]=\"picker1\" formControlName=\"start\"\n placeholder=\"Starts date\"\n >\n <mat-datepicker-toggle matIconSuffix [for]=\"picker1\"></mat-datepicker-toggle>\n <mat-datepicker\n [disabled]=\"disabled\"\n #picker1\n [startAt]=\"inputGroup.controls.start.defaultValue\"\n [startView]=\"startView\"\n (monthSelected)=\"setStart($event, picker1)\"\n\n >\n </mat-datepicker>\n </mat-form-field>\n <!-- /start date -->\n <!-- end date -->\n <mat-form-field>\n <mat-label>Zeitpunkt2</mat-label>\n <input matInput\n [disabled]=\"disabled\"\n [min]=\"inputGroup.controls.start.defaultValue\"\n [max]=\"inputGroup.controls.end.defaultValue\"\n [matDatepicker]=\"picker2\"\n formControlName=\"end\"\n placeholder=\"End date\"\n >\n <mat-datepicker-toggle matIconSuffix [for]=\"picker2\"></mat-datepicker-toggle>\n <mat-datepicker\n [disabled]=\"disabled\"\n #picker2\n [startAt]=\"inputGroup.controls.end.value\"\n [startView]=\"startView\"\n (monthSelected)=\"setEnd($event, picker2)\"\n >\n </mat-datepicker>\n </mat-form-field>\n <!-- /end date -->\n</div>\n<!--\n </mat-card-content>\n</mat-card>\n-->\n" }]
3542
- }], ctorParameters: () => [], propDecorators: { startView: [{
3542
+ }], propDecorators: { startView: [{
3543
3543
  type: Input
3544
3544
  }], inputGroup: [{
3545
3545
  type: Input,
@@ -3549,7 +3549,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3549
3549
  }], start: [{
3550
3550
  type: ViewChild,
3551
3551
  args: ['start', {
3552
- read: ElementRef,
3552
+ read: (ElementRef),
3553
3553
  static: true,
3554
3554
  }]
3555
3555
  }], ripple: [{
@@ -3676,20 +3676,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3676
3676
  type: Input
3677
3677
  }] } });
3678
3678
 
3679
- class CountsWithHistoryComponent {
3680
- constructor(metaApi, destroyRef, linkService) {
3681
- this.metaApi = metaApi;
3682
- this.destroyRef = destroyRef;
3683
- this.linkService = linkService;
3679
+ class BaseHistoricDataTableDirective {
3680
+ constructor() {
3681
+ this.metaApi = inject(MetaApiService);
3682
+ this.destroyRef = inject(DestroyRef);
3683
+ this.linkService = inject(EditorialLinkService);
3684
+ this.columnTranslationkey = null;
3684
3685
  this.loadingCount = signal(0);
3685
3686
  this.isLoading = computed(() => this.loadingCount() > 0);
3687
+ this.isHistoryEnabled = signal(false);
3688
+ this.isHistoryEnabled$ = toObservable(this.isHistoryEnabled);
3686
3689
  this.timeFilterLoaded = signal(false);
3687
3690
  this.recentTypeCount$ = new BehaviorSubject({ columns: [], rows: [] });
3688
3691
  this.pastTypeCount$ = new BehaviorSubject({ columns: [], rows: [] });
3689
3692
  this.DateTime = DateTime;
3690
3693
  this.columns = signal([]);
3691
- this.apiMethod = 'getMaterialTypeCountsByReplicationSource';
3692
- this.columnTranslationkey = null;
3694
+ this.dataForPastData$ = new Subject();
3695
+ this.dataForRecentData$ = new Subject();
3696
+ this.startValues$ = this.dataForPastData$.pipe(filter((data) => this.validateLoadingData(data)), distinctUntilChanged((a, b) => this.compareLoadingDataEqual(a, b)), throttleTime(500), switchMap((start) => this.getCountByDate(start)), tap((it) => this.pastTypeCount$.next(it)), takeUntilDestroyed(this.destroyRef));
3697
+ this.endValues$ = this.dataForRecentData$.pipe(filter((data) => this.validateLoadingData(data)), distinctUntilChanged((a, b) => this.compareLoadingDataEqual(a, b)), throttleTime(500), switchMap((end) => this.getCountByDate(end)), tap((it) => this.recentTypeCount$.next(it)), tap((it) => this.columns.set(it.columns.slice())), takeUntilDestroyed(this.destroyRef));
3693
3698
  /* In this widget's backend we do have data for today
3694
3699
  * therefore we set the end date to today and use the timerange() endpoint to only set the start date
3695
3700
  */
@@ -3697,7 +3702,11 @@ class CountsWithHistoryComponent {
3697
3702
  start: new FormControl(),
3698
3703
  end: new FormControl(DateTime.utc().startOf('day'), { nonNullable: true }),
3699
3704
  });
3700
- this.isHistoryEnabled = signal(false);
3705
+ this.timerangeStart$ = of(undefined).pipe(switchMap(() => this.getAvailableDateRange()), take(1), map((rangeFilter) => this.getStartDateOfRange(rangeFilter)), tap((startDate) => {
3706
+ //this is to have a default value for the start date => the min date of the range
3707
+ this.range.setControl('start', new FormControl(startDate, { nonNullable: true }));
3708
+ this.timeFilterLoaded.set(true);
3709
+ }), takeUntilDestroyed(this.destroyRef));
3701
3710
  this.allColumns = computed(() => {
3702
3711
  if (!this.isHistoryEnabled()) {
3703
3712
  return this.recentColumns();
@@ -3713,39 +3722,9 @@ class CountsWithHistoryComponent {
3713
3722
  this.pastColumns = computed(() => {
3714
3723
  return this.columns().map((c) => c.id + '_past');
3715
3724
  });
3716
- effect(() => {
3717
- this.range.controls.end.reset();
3718
- if (!this.isHistoryEnabled()) {
3719
- this.range.controls.start.setValue(this.range.controls.end.value.startOf('day'));
3720
- }
3721
- else {
3722
- this.range.controls.start.reset();
3723
- }
3724
- });
3725
3725
  }
3726
- ngOnInit() {
3727
- this.getAvailableDateRange()
3728
- .pipe(tap((rangeFilter) => {
3729
- const startDate = this.getStartDateOfRange(rangeFilter);
3730
- //this is to have a default value for the start date => the min date of the range
3731
- this.range.setControl('start', new FormControl(startDate, { nonNullable: true }));
3732
- }), finalize(() => {
3733
- this.timeFilterLoaded.set(true);
3734
- this.range.controls.start.reset();
3735
- }), takeUntilDestroyed(this.destroyRef))
3736
- .subscribe();
3737
- this.getCountByDate(this.range.controls.end.value)
3738
- .pipe(tap((response) => {
3739
- this.columns.set(response.columns.slice());
3740
- this.recentTypeCount$.next(response);
3741
- }), takeUntilDestroyed(this.destroyRef))
3742
- .subscribe();
3743
- this.getValuesInDateRange()
3744
- .pipe(tap(([past, recent]) => {
3745
- this.pastTypeCount$.next(past);
3746
- this.recentTypeCount$.next(recent);
3747
- }), takeUntilDestroyed(this.destroyRef))
3748
- .subscribe();
3726
+ getAvailableDateRange() {
3727
+ return of(undefined).pipe(tap(() => this.loadingCount.update((it) => it + 1)), switchMap(() => this.metaApi.getTimerangeFilter()), filter((filter) => filter != null), tap(() => this.loadingCount.update((it) => it - 1)));
3749
3728
  }
3750
3729
  getStartDateOfRange(rangeFilter) {
3751
3730
  return DateTime.fromISO(rangeFilter.values.find((v) => v.id === 'rangeStart')?.label, {
@@ -3755,26 +3734,6 @@ class CountsWithHistoryComponent {
3755
3734
  columnIdent(_index, col) {
3756
3735
  return col.id;
3757
3736
  }
3758
- getAvailableDateRange() {
3759
- this.loadingCount.update((it) => it + 1);
3760
- return this.metaApi.getTimerangeFilter().pipe(filter((filter) => filter != null), finalize(() => this.loadingCount.update((it) => it - 1)));
3761
- }
3762
- getValuesInDateRange() {
3763
- return this.range.valueChanges.pipe(filter((range) => !!range.start?.isValid && !!range.end?.isValid), switchMap((range) => {
3764
- return zip(this.getCountByDate(range.start), this.getCountByDate(range.end));
3765
- }));
3766
- }
3767
- getCountByDate(date) {
3768
- this.loadingCount.update((it) => it + 1);
3769
- const filter = {
3770
- field: 'asOf',
3771
- values: [{ id: date.toISO({ includeOffset: false }), label: '' }],
3772
- };
3773
- return this.metaApi[this.apiMethod]([filter]).pipe(finalize(() => this.loadingCount.update((it) => it - 1)), map((response) => ({
3774
- ...response,
3775
- rows: response.rows.toSorted((a, b) => a.meta.label.localeCompare(b.meta.label)),
3776
- })));
3777
- }
3778
3737
  pastTypeCount(row, columnid) {
3779
3738
  if (!this.pastTypeCount$.value.rows.length) {
3780
3739
  return {};
@@ -3799,8 +3758,75 @@ class CountsWithHistoryComponent {
3799
3758
  return this.linkService.createLinkForCountsWithHistory(this.sourceType, sourceId, issueId);
3800
3759
  }));
3801
3760
  }
3802
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CountsWithHistoryComponent, deps: [{ token: MetaApiService }, { token: i0.DestroyRef }, { token: EditorialLinkService }], target: i0.ɵɵFactoryTarget.Component }); }
3803
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: CountsWithHistoryComponent, isStandalone: true, selector: "metaqs2-counts-with-history", inputs: { apiMethod: "apiMethod", columnTranslationkey: "columnTranslationkey", pageTitle: "pageTitle", sourceType: "sourceType" }, ngImport: i0, template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title data-test-id=\"page-title\">\n Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{ isLoading() ? \": Lade neue Daten.\" : \"\" }}\n </mat-card-title>\n </mat-card-header>\n <!-- consider to put the filter in the table header to avoid that it is scrolled out of view-->\n <!-- show the filter after the values are loaded to avoid loading current data twice -->\n <mat-card-content class=\"toolbar\">\n <div style=\"flex: 1 1 auto\"></div>\n <metaqs2-datepicker style=\"display: inline-block\" matRipple #datepickerRipple=\"matRipple\" [disabled]=\"isLoading() || !isHistoryEnabled()\" [inputGroup]=\"range\" *ngIf=\"timeFilterLoaded() && isHistoryEnabled()\"></metaqs2-datepicker>\n <mat-slide-toggle [ngModel]=\"isHistoryEnabled()\" (ngModelChange)=\"isHistoryEnabled.set($event)\" [disabled]=\"isLoading()\" *ngIf=\"timeFilterLoaded()\">\n <label>Zeige historische Daten</label>\n </mat-slide-toggle>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentTypeCount$.value.rows\"\n class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"label-col\" sticky>\n <th [attr.rowspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef>\n <div>Quelle</div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n [matTooltip]=\"row.meta.alt_label\"\n class=\"label-col mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{ row.meta.label }}\n </td>\n </ng-container>\n <!-- one column for each type -->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_type'\">\n <th [attr.colspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef [matTooltip]=\"col.label\">\n {{ columnTranslationkey ? (columnTranslationkey + col.label | translate) : col.label }}\n </th>\n </ng-container>\n <!-- one column for each type for the most current date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_recent'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef\n matTooltip=\"no tooltip\">{{ range.controls.end.value.toLocaleString(DateTime.DATE_SHORT) }}\n </th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\">\n <a [attr.href]=\"openInEditor(row.meta.id, col.id) | async\" target=\"editor_frontend\">{{ row.counts[col.id] ?? '\u2013' }}</a>\n </td>\n </ng-container>\n <!-- one column for each type for the older date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_past'\">\n <th class=\"past-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"no tooltip\">\n {{ (pastTypeCount$ | async)?.rows?.length ? range.controls.start.value.toLocaleString(DateTime.DATE_SHORT) : 'no past data' }}\n </th>\n <td class=\"past-data-cell\" mat-cell *matCellDef=\"let row;\" >\n <ng-container *ngIf=\"(pastTypeCount$ | async)?.rows?.length && pastTypeCount(row, col.id) as trend\">\n <span [class]=\"trend.trend\"> {{ trend.value ?? '\u2013' }}\n <mat-icon *ngIf=\"trend.value\" aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" /></span>\n <span class=\"cdk-visually-hidden\">{{ trend.trend }}</span>\n </ng-container>\n </td>\n </ng-container>\n <!-- generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['label-col'].concat(typeColumns()); sticky:true;\"></tr>\n <tr [hidden]=\"!isHistoryEnabled()\" mat-header-row *matHeaderRowDef=\"allColumns(); sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['label-col'].concat(allColumns())\"></tr>\n\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}tr:nth-child(2n){background-color:#e4e4e4}tr:nth-child(2n)>td.label-col,tr:nth-child(2n) td.recent-data-cell{border-right:1px solid white}tr:nth-child(odd){background-color:#fff}tr:nth-child(odd)>td.label-col,tr:nth-child(odd) td.recent-data-cell{border-right:1px solid #e4e4e4}td.label-col{text-align:left}.mat-mdc-header-cell,.mat-mdc-cell{text-align:center}.mat-mdc-header-cell a[href],.mat-mdc-cell a[href]{color:var(--mat-table-row-item-label-text-color);cursor:pointer;text-decoration:underline}.mat-mdc-header-cell a[href]:hover,.mat-mdc-cell a[href]:hover{text-decoration:underline}.mat-mdc-header-cell mat-icon,.mat-mdc-cell mat-icon{margin-left:5px;vertical-align:middle}.trending_down{color:#4abeff}.trending_up{color:#c20808}.toolbar,.actionbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$1.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i3$1.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i3$1.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i4.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$3.TranslatePipe, name: "translate" }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: DatepickerComponent, selector: "metaqs2-datepicker", inputs: ["disabled", "inputGroup"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "component", type: ProgressSpinnerComponent, selector: "metaqs2-progress-spinner", inputs: ["color", "diameter", "strokeWidth", "backdropEnabled", "positionGloballyCenter", "displayProgressSpinner"] }, { kind: "directive", type: MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }] }); }
3761
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseHistoricDataTableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3762
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: BaseHistoricDataTableDirective, inputs: { apiMethod: "apiMethod", columnTranslationkey: "columnTranslationkey", pageTitle: "pageTitle", sourceType: "sourceType" }, ngImport: i0 }); }
3763
+ }
3764
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseHistoricDataTableDirective, decorators: [{
3765
+ type: Directive
3766
+ }], propDecorators: { apiMethod: [{
3767
+ type: Input
3768
+ }], columnTranslationkey: [{
3769
+ type: Input
3770
+ }], pageTitle: [{
3771
+ type: Input
3772
+ }], sourceType: [{
3773
+ type: Input,
3774
+ args: [{ required: true }]
3775
+ }] } });
3776
+ class CountsWithHistoryComponent extends BaseHistoricDataTableDirective {
3777
+ ngOnInit() {
3778
+ this.apiMethod ??= 'getMaterialTypeCountsByReplicationSource';
3779
+ this.range.valueChanges
3780
+ .pipe(tap((data) => {
3781
+ this.dataForPastData$.next({ date: data.start });
3782
+ this.dataForRecentData$.next({ date: data.end });
3783
+ }), takeUntilDestroyed(this.destroyRef))
3784
+ .subscribe();
3785
+ this.isHistoryEnabled$
3786
+ .pipe(tap((enabled) => {
3787
+ this.range.controls.end.reset();
3788
+ if (!enabled) {
3789
+ this.startDateSubscription?.unsubscribe();
3790
+ this.startValuesSubscription?.unsubscribe();
3791
+ return;
3792
+ }
3793
+ this.range.controls.start.reset();
3794
+ if (!this.timeFilterLoaded()) {
3795
+ this.startDateSubscription = this.timerangeStart$
3796
+ .pipe(take(1), tap(() => {
3797
+ this.startValuesSubscription = this.startValues$.subscribe();
3798
+ this.range.controls.start.reset();
3799
+ }))
3800
+ .subscribe();
3801
+ }
3802
+ else {
3803
+ this.startValuesSubscription = this.startValues$.subscribe();
3804
+ this.range.controls.start.reset();
3805
+ }
3806
+ }), takeUntilDestroyed(this.destroyRef))
3807
+ .subscribe();
3808
+ this.endValues$.subscribe();
3809
+ }
3810
+ getCountByDate(data) {
3811
+ const filter = {
3812
+ field: 'asOf',
3813
+ values: [{ id: data.date.toISO({ includeOffset: false }), label: '' }],
3814
+ };
3815
+ return of(undefined).pipe(tap(() => this.loadingCount.update((it) => it + 1)), switchMap(() => {
3816
+ return this.metaApi[this.apiMethod]([filter]).pipe(finalize(() => this.loadingCount.update((it) => it - 1)));
3817
+ }), map((response) => ({
3818
+ ...response,
3819
+ rows: response.rows.toSorted((a, b) => a.meta.label.localeCompare(b.meta.label)),
3820
+ })));
3821
+ }
3822
+ validateLoadingData(data) {
3823
+ return data.date?.isValid ?? false;
3824
+ }
3825
+ compareLoadingDataEqual(a, b) {
3826
+ return a.date.equals(b.date);
3827
+ }
3828
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CountsWithHistoryComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3829
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: CountsWithHistoryComponent, isStandalone: true, selector: "metaqs2-counts-with-history", usesInheritance: true, ngImport: i0, template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title data-test-id=\"page-title\">\n Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{ isLoading() ? \": Lade neue Daten.\" : \"\" }}\n </mat-card-title>\n </mat-card-header>\n <!-- consider to put the filter in the table header to avoid that it is scrolled out of view-->\n <!-- show the filter after the values are loaded to avoid loading current data twice -->\n <mat-card-content class=\"toolbar\">\n <metaqs2-datepicker style=\"display: inline-block\" matRipple [disabled]=\"isLoading() || !isHistoryEnabled()\" [inputGroup]=\"range\" *ngIf=\"timeFilterLoaded() && isHistoryEnabled()\"></metaqs2-datepicker>\n <div style=\"flex: 1 1 auto\"></div>\n <mat-slide-toggle [ngModel]=\"isHistoryEnabled()\" (ngModelChange)=\"isHistoryEnabled.set($event)\" [disabled]=\"isLoading()\">\n <label>Zeige historische Daten</label>\n </mat-slide-toggle>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentTypeCount$.value.rows\"\n class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"label-col\" sticky>\n <th [attr.rowspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef>\n <div>Quelle</div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n [matTooltip]=\"row.meta.alt_label\"\n class=\"label-col mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{ row.meta.label }}\n </td>\n </ng-container>\n <!-- one column for each type -->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_type'\">\n <th [attr.colspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef [matTooltip]=\"col.label\">\n {{ columnTranslationkey ? (columnTranslationkey + col.label | translate) : col.label }}\n </th>\n </ng-container>\n <!-- one column for each type for the most current date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_recent'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef\n matTooltip=\"no tooltip\">{{ range.controls.end.value.toLocaleString(DateTime.DATE_SHORT) }}\n </th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\">\n <a [attr.href]=\"openInEditor(row.meta.id, col.id) | async\" target=\"editor_frontend\">{{ row.counts[col.id] ?? '\u2013' }}</a>\n </td>\n </ng-container>\n <!-- one column for each type for the older date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_past'\">\n <th class=\"past-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"no tooltip\">\n {{ (pastTypeCount$ | async)?.rows?.length ? range.controls.start.value.toLocaleString(DateTime.DATE_SHORT) : 'no past data' }}\n </th>\n <td class=\"past-data-cell\" mat-cell *matCellDef=\"let row;\" >\n <ng-container *ngIf=\"(pastTypeCount$ | async)?.rows?.length && pastTypeCount(row, col.id) as trend\">\n <span [class]=\"trend.trend\"> {{ trend.value ?? '\u2013' }}\n <mat-icon *ngIf=\"trend.value\" aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" /></span>\n <span class=\"cdk-visually-hidden\">{{ trend.trend }}</span>\n </ng-container>\n </td>\n </ng-container>\n <!-- generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['label-col'].concat(typeColumns()); sticky:true;\"></tr>\n <tr [hidden]=\"!isHistoryEnabled()\" mat-header-row *matHeaderRowDef=\"allColumns(); sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['label-col'].concat(allColumns())\"></tr>\n\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}tr:nth-child(2n){background-color:#e4e4e4}tr:nth-child(2n)>td.label-col,tr:nth-child(2n) td.recent-data-cell{border-right:1px solid white}tr:nth-child(odd){background-color:#fff}tr:nth-child(odd)>td.label-col,tr:nth-child(odd) td.recent-data-cell{border-right:1px solid #e4e4e4}td.label-col{text-align:left}.mat-mdc-header-cell,.mat-mdc-cell{text-align:center}.mat-mdc-header-cell a[href],.mat-mdc-cell a[href]{color:var(--mat-table-row-item-label-text-color);cursor:pointer;text-decoration:underline}.mat-mdc-header-cell a[href]:hover,.mat-mdc-cell a[href]:hover{text-decoration:underline}.mat-mdc-header-cell mat-icon,.mat-mdc-cell mat-icon{margin-left:5px;vertical-align:middle}.trending_down{color:#4abeff}.trending_up{color:#c20808}.toolbar,.actionbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$1.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i3$1.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i3$1.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i5$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i5$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i5$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i5$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i5$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i5$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i5$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i5$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i5$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i5$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$3.TranslatePipe, name: "translate" }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: DatepickerComponent, selector: "metaqs2-datepicker", inputs: ["disabled", "inputGroup"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "component", type: ProgressSpinnerComponent, selector: "metaqs2-progress-spinner", inputs: ["color", "diameter", "strokeWidth", "backdropEnabled", "positionGloballyCenter", "displayProgressSpinner"] }, { kind: "directive", type: MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }] }); }
3804
3830
  }
3805
3831
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CountsWithHistoryComponent, decorators: [{
3806
3832
  type: Component,
@@ -3827,18 +3853,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3827
3853
  AsyncPipe,
3828
3854
  ProgressSpinnerComponent,
3829
3855
  MatRipple,
3830
- ], template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title data-test-id=\"page-title\">\n Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{ isLoading() ? \": Lade neue Daten.\" : \"\" }}\n </mat-card-title>\n </mat-card-header>\n <!-- consider to put the filter in the table header to avoid that it is scrolled out of view-->\n <!-- show the filter after the values are loaded to avoid loading current data twice -->\n <mat-card-content class=\"toolbar\">\n <div style=\"flex: 1 1 auto\"></div>\n <metaqs2-datepicker style=\"display: inline-block\" matRipple #datepickerRipple=\"matRipple\" [disabled]=\"isLoading() || !isHistoryEnabled()\" [inputGroup]=\"range\" *ngIf=\"timeFilterLoaded() && isHistoryEnabled()\"></metaqs2-datepicker>\n <mat-slide-toggle [ngModel]=\"isHistoryEnabled()\" (ngModelChange)=\"isHistoryEnabled.set($event)\" [disabled]=\"isLoading()\" *ngIf=\"timeFilterLoaded()\">\n <label>Zeige historische Daten</label>\n </mat-slide-toggle>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentTypeCount$.value.rows\"\n class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"label-col\" sticky>\n <th [attr.rowspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef>\n <div>Quelle</div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n [matTooltip]=\"row.meta.alt_label\"\n class=\"label-col mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{ row.meta.label }}\n </td>\n </ng-container>\n <!-- one column for each type -->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_type'\">\n <th [attr.colspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef [matTooltip]=\"col.label\">\n {{ columnTranslationkey ? (columnTranslationkey + col.label | translate) : col.label }}\n </th>\n </ng-container>\n <!-- one column for each type for the most current date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_recent'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef\n matTooltip=\"no tooltip\">{{ range.controls.end.value.toLocaleString(DateTime.DATE_SHORT) }}\n </th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\">\n <a [attr.href]=\"openInEditor(row.meta.id, col.id) | async\" target=\"editor_frontend\">{{ row.counts[col.id] ?? '\u2013' }}</a>\n </td>\n </ng-container>\n <!-- one column for each type for the older date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_past'\">\n <th class=\"past-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"no tooltip\">\n {{ (pastTypeCount$ | async)?.rows?.length ? range.controls.start.value.toLocaleString(DateTime.DATE_SHORT) : 'no past data' }}\n </th>\n <td class=\"past-data-cell\" mat-cell *matCellDef=\"let row;\" >\n <ng-container *ngIf=\"(pastTypeCount$ | async)?.rows?.length && pastTypeCount(row, col.id) as trend\">\n <span [class]=\"trend.trend\"> {{ trend.value ?? '\u2013' }}\n <mat-icon *ngIf=\"trend.value\" aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" /></span>\n <span class=\"cdk-visually-hidden\">{{ trend.trend }}</span>\n </ng-container>\n </td>\n </ng-container>\n <!-- generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['label-col'].concat(typeColumns()); sticky:true;\"></tr>\n <tr [hidden]=\"!isHistoryEnabled()\" mat-header-row *matHeaderRowDef=\"allColumns(); sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['label-col'].concat(allColumns())\"></tr>\n\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}tr:nth-child(2n){background-color:#e4e4e4}tr:nth-child(2n)>td.label-col,tr:nth-child(2n) td.recent-data-cell{border-right:1px solid white}tr:nth-child(odd){background-color:#fff}tr:nth-child(odd)>td.label-col,tr:nth-child(odd) td.recent-data-cell{border-right:1px solid #e4e4e4}td.label-col{text-align:left}.mat-mdc-header-cell,.mat-mdc-cell{text-align:center}.mat-mdc-header-cell a[href],.mat-mdc-cell a[href]{color:var(--mat-table-row-item-label-text-color);cursor:pointer;text-decoration:underline}.mat-mdc-header-cell a[href]:hover,.mat-mdc-cell a[href]:hover{text-decoration:underline}.mat-mdc-header-cell mat-icon,.mat-mdc-cell mat-icon{margin-left:5px;vertical-align:middle}.trending_down{color:#4abeff}.trending_up{color:#c20808}.toolbar,.actionbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:.5rem}\n"] }]
3831
- }], ctorParameters: () => [{ type: MetaApiService }, { type: i0.DestroyRef }, { type: EditorialLinkService }], propDecorators: { apiMethod: [{
3832
- type: Input,
3833
- args: [{ required: true }]
3834
- }], columnTranslationkey: [{
3835
- type: Input
3836
- }], pageTitle: [{
3837
- type: Input
3838
- }], sourceType: [{
3839
- type: Input,
3840
- args: [{ required: true }]
3841
- }] } });
3856
+ ], template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title data-test-id=\"page-title\">\n Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{ isLoading() ? \": Lade neue Daten.\" : \"\" }}\n </mat-card-title>\n </mat-card-header>\n <!-- consider to put the filter in the table header to avoid that it is scrolled out of view-->\n <!-- show the filter after the values are loaded to avoid loading current data twice -->\n <mat-card-content class=\"toolbar\">\n <metaqs2-datepicker style=\"display: inline-block\" matRipple [disabled]=\"isLoading() || !isHistoryEnabled()\" [inputGroup]=\"range\" *ngIf=\"timeFilterLoaded() && isHistoryEnabled()\"></metaqs2-datepicker>\n <div style=\"flex: 1 1 auto\"></div>\n <mat-slide-toggle [ngModel]=\"isHistoryEnabled()\" (ngModelChange)=\"isHistoryEnabled.set($event)\" [disabled]=\"isLoading()\">\n <label>Zeige historische Daten</label>\n </mat-slide-toggle>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentTypeCount$.value.rows\"\n class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"label-col\" sticky>\n <th [attr.rowspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef>\n <div>Quelle</div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n [matTooltip]=\"row.meta.alt_label\"\n class=\"label-col mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{ row.meta.label }}\n </td>\n </ng-container>\n <!-- one column for each type -->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_type'\">\n <th [attr.colspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef [matTooltip]=\"col.label\">\n {{ columnTranslationkey ? (columnTranslationkey + col.label | translate) : col.label }}\n </th>\n </ng-container>\n <!-- one column for each type for the most current date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_recent'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef\n matTooltip=\"no tooltip\">{{ range.controls.end.value.toLocaleString(DateTime.DATE_SHORT) }}\n </th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\">\n <a [attr.href]=\"openInEditor(row.meta.id, col.id) | async\" target=\"editor_frontend\">{{ row.counts[col.id] ?? '\u2013' }}</a>\n </td>\n </ng-container>\n <!-- one column for each type for the older date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_past'\">\n <th class=\"past-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"no tooltip\">\n {{ (pastTypeCount$ | async)?.rows?.length ? range.controls.start.value.toLocaleString(DateTime.DATE_SHORT) : 'no past data' }}\n </th>\n <td class=\"past-data-cell\" mat-cell *matCellDef=\"let row;\" >\n <ng-container *ngIf=\"(pastTypeCount$ | async)?.rows?.length && pastTypeCount(row, col.id) as trend\">\n <span [class]=\"trend.trend\"> {{ trend.value ?? '\u2013' }}\n <mat-icon *ngIf=\"trend.value\" aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" /></span>\n <span class=\"cdk-visually-hidden\">{{ trend.trend }}</span>\n </ng-container>\n </td>\n </ng-container>\n <!-- generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['label-col'].concat(typeColumns()); sticky:true;\"></tr>\n <tr [hidden]=\"!isHistoryEnabled()\" mat-header-row *matHeaderRowDef=\"allColumns(); sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['label-col'].concat(allColumns())\"></tr>\n\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}tr:nth-child(2n){background-color:#e4e4e4}tr:nth-child(2n)>td.label-col,tr:nth-child(2n) td.recent-data-cell{border-right:1px solid white}tr:nth-child(odd){background-color:#fff}tr:nth-child(odd)>td.label-col,tr:nth-child(odd) td.recent-data-cell{border-right:1px solid #e4e4e4}td.label-col{text-align:left}.mat-mdc-header-cell,.mat-mdc-cell{text-align:center}.mat-mdc-header-cell a[href],.mat-mdc-cell a[href]{color:var(--mat-table-row-item-label-text-color);cursor:pointer;text-decoration:underline}.mat-mdc-header-cell a[href]:hover,.mat-mdc-cell a[href]:hover{text-decoration:underline}.mat-mdc-header-cell mat-icon,.mat-mdc-cell mat-icon{margin-left:5px;vertical-align:middle}.trending_down{color:#4abeff}.trending_up{color:#c20808}.toolbar,.actionbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:.5rem}\n"] }]
3857
+ }] });
3842
3858
 
3843
3859
  async function createRegister(environment) {
3844
3860
  if (environment.production) {
@@ -3868,32 +3884,29 @@ async function createRegister(environment) {
3868
3884
  };
3869
3885
  }
3870
3886
 
3871
- class TreeLicenseComponent extends CountsWithHistoryComponent {
3887
+ class TreeLicenseComponent extends BaseHistoricDataTableDirective {
3872
3888
  constructor() {
3873
3889
  super(...arguments);
3874
3890
  this.colId$ = new BehaviorSubject('defaultCollection');
3875
3891
  this.sourceType = 'collection';
3876
- this.apiMethod = 'getLicenseCountsByLicenseGroup';
3877
3892
  }
3878
3893
  set collectionId(id) {
3879
3894
  this.colId$.next(id);
3880
3895
  }
3881
- getCountByDate(date) {
3882
- this.loadingCount.update((it) => it + 1);
3896
+ getCountByDate(data) {
3883
3897
  const filter = {
3884
3898
  field: 'asOf',
3885
- values: [{ id: date.toISO({ includeOffset: false }), label: '' }],
3899
+ values: [{ id: data.date.toISO({ includeOffset: false }), label: '' }],
3886
3900
  };
3887
- return this.metaApi[this.apiMethod](this.colId$.getValue(), [filter]).pipe(finalize(() => this.loadingCount.update((it) => it - 1)), map((response) => {
3901
+ return of(undefined).pipe(tap(() => this.loadingCount.update((it) => it + 1)), switchMap(() => {
3902
+ return this.metaApi[this.apiMethod](this.colId$.getValue(), [filter]).pipe(finalize(() => this.loadingCount.update((it) => it - 1)));
3903
+ }), map((response) => {
3888
3904
  const castedRows = response.rows.map((row) => row);
3889
3905
  return {
3890
3906
  ...response,
3891
3907
  // return the sufficient part of the counts, because the api return a QualityMatrix not a MatrixWithCounts
3892
3908
  rows: castedRows.map((row) => {
3893
- const counts = Object.entries(row.counts).reduce((acc, [key, count]) => {
3894
- acc[key] = count.sufficient;
3895
- return acc;
3896
- }, {});
3909
+ const counts = Object.fromEntries(Object.entries(row.counts).map(([key, value]) => [key, value.sufficient]));
3897
3910
  return {
3898
3911
  ...row,
3899
3912
  counts,
@@ -3903,20 +3916,52 @@ class TreeLicenseComponent extends CountsWithHistoryComponent {
3903
3916
  }));
3904
3917
  }
3905
3918
  ngOnInit() {
3906
- this.colId$
3907
- .pipe(filter((colid) => colid !== undefined), filter(() => {
3908
- return this.range.controls.start.value !== null && this.range.controls.end.value !== null;
3909
- }), switchMap(() => {
3910
- return zip(this.getCountByDate(this.range.controls.start.getRawValue()), this.getCountByDate(this.range.controls.end.getRawValue()));
3911
- }), tap(([past, recent]) => {
3912
- this.pastTypeCount$.next(past);
3913
- this.recentTypeCount$.next(recent);
3919
+ this.apiMethod ??= 'getLicenseCountsByLicenseGroup';
3920
+ combineLatest([this.colId$, this.range.valueChanges])
3921
+ .pipe(tap(([collectionId, range]) => {
3922
+ this.dataForPastData$.next({
3923
+ date: range.start,
3924
+ collectionId: collectionId,
3925
+ });
3926
+ this.dataForRecentData$.next({
3927
+ date: range.end,
3928
+ collectionId: collectionId,
3929
+ });
3930
+ }), takeUntilDestroyed(this.destroyRef))
3931
+ .subscribe();
3932
+ this.isHistoryEnabled$
3933
+ .pipe(tap((enabled) => {
3934
+ this.range.controls.end.reset();
3935
+ if (!enabled) {
3936
+ this.startDateSubscription?.unsubscribe();
3937
+ this.startValuesSubscription?.unsubscribe();
3938
+ return;
3939
+ }
3940
+ this.range.controls.start.reset();
3941
+ if (!this.timeFilterLoaded()) {
3942
+ this.startDateSubscription = this.timerangeStart$
3943
+ .pipe(take(1), tap(() => {
3944
+ this.startValuesSubscription = this.startValues$.subscribe();
3945
+ this.range.controls.start.reset();
3946
+ }))
3947
+ .subscribe();
3948
+ }
3949
+ else {
3950
+ this.startValuesSubscription = this.startValues$.subscribe();
3951
+ this.range.controls.start.reset();
3952
+ }
3914
3953
  }), takeUntilDestroyed(this.destroyRef))
3915
3954
  .subscribe();
3916
- super.ngOnInit();
3955
+ this.endValues$.subscribe();
3956
+ }
3957
+ validateLoadingData(data) {
3958
+ return !!data?.collectionId && (data.date?.isValid ?? false);
3959
+ }
3960
+ compareLoadingDataEqual(a, b) {
3961
+ return a.collectionId === b.collectionId && a.date.equals(b.date);
3917
3962
  }
3918
3963
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeLicenseComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3919
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TreeLicenseComponent, isStandalone: true, selector: "metaqs2-tree-license", inputs: { collectionId: "collectionId", sourceType: "sourceType", apiMethod: "apiMethod" }, usesInheritance: true, ngImport: i0, template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title data-test-id=\"page-title\">\n Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{ isLoading() ? \": Lade neue Daten.\" : \"\" }}\n </mat-card-title>\n </mat-card-header>\n <!-- consider to put the filter in the table header to avoid that it is scrolled out of view-->\n <!-- show the filter after the values are loaded to avoid loading current data twice -->\n <mat-card-content class=\"toolbar\">\n <div style=\"flex: 1 1 auto\"></div>\n <metaqs2-datepicker style=\"display: inline-block\" matRipple #datepickerRipple=\"matRipple\" [disabled]=\"isLoading() || !isHistoryEnabled()\" [inputGroup]=\"range\" *ngIf=\"timeFilterLoaded() && isHistoryEnabled()\"></metaqs2-datepicker>\n <mat-slide-toggle [ngModel]=\"isHistoryEnabled()\" (ngModelChange)=\"isHistoryEnabled.set($event)\" [disabled]=\"isLoading()\" *ngIf=\"timeFilterLoaded()\">\n <label>Zeige historische Daten</label>\n </mat-slide-toggle>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentTypeCount$.value.rows\"\n class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"label-col\" sticky>\n <th [attr.rowspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef>\n <div>Quelle</div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n [matTooltip]=\"row.meta.alt_label\"\n class=\"label-col mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{ row.meta.label }}\n </td>\n </ng-container>\n <!-- one column for each type -->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_type'\">\n <th [attr.colspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef [matTooltip]=\"col.label\">\n {{ columnTranslationkey ? (columnTranslationkey + col.label | translate) : col.label }}\n </th>\n </ng-container>\n <!-- one column for each type for the most current date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_recent'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef\n matTooltip=\"no tooltip\">{{ range.controls.end.value.toLocaleString(DateTime.DATE_SHORT) }}\n </th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\">\n <a [attr.href]=\"openInEditor(row.meta.id, col.id) | async\" target=\"editor_frontend\">{{ row.counts[col.id] ?? '\u2013' }}</a>\n </td>\n </ng-container>\n <!-- one column for each type for the older date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_past'\">\n <th class=\"past-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"no tooltip\">\n {{ (pastTypeCount$ | async)?.rows?.length ? range.controls.start.value.toLocaleString(DateTime.DATE_SHORT) : 'no past data' }}\n </th>\n <td class=\"past-data-cell\" mat-cell *matCellDef=\"let row;\" >\n <ng-container *ngIf=\"(pastTypeCount$ | async)?.rows?.length && pastTypeCount(row, col.id) as trend\">\n <span [class]=\"trend.trend\"> {{ trend.value ?? '\u2013' }}\n <mat-icon *ngIf=\"trend.value\" aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" /></span>\n <span class=\"cdk-visually-hidden\">{{ trend.trend }}</span>\n </ng-container>\n </td>\n </ng-container>\n <!-- generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['label-col'].concat(typeColumns()); sticky:true;\"></tr>\n <tr [hidden]=\"!isHistoryEnabled()\" mat-header-row *matHeaderRowDef=\"allColumns(); sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['label-col'].concat(allColumns())\"></tr>\n\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}.mat-cell-level-1{padding-left:20px!important;text-align:left}.mat-cell-level-1:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-2{padding-left:40px!important;text-align:left}.mat-cell-level-2:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-3{padding-left:60px!important;text-align:left}.mat-cell-level-3:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-4{padding-left:80px!important;text-align:left}.mat-cell-level-4:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-5{padding-left:100px!important;text-align:left}.mat-cell-level-5:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-6{padding-left:120px!important;text-align:left}.mat-cell-level-6:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-7{padding-left:140px!important;text-align:left}.mat-cell-level-7:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-8{padding-left:160px!important;text-align:left}.mat-cell-level-8:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-2:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PHBhdGggb3BhY2l0eT0iMC4zIiBkPSJNMTkgMTAuM0wxMiAxNi4zTDUgMTAuM0wxMiA0LjE5OTk1TDE5IDEwLjNaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+)}.mat-cell-level-0:before,.mat-cell-level-1:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNCAxMi45TDMgMTMuOEwxMSAyMC43QzExLjYgMjEuMiAxMi40IDIxLjIgMTMgMjAuN0wyMSAxMy44TDIwIDEyLjlMMTIgMTkuOEw0IDEyLjlaTTExIDMuNDAwMDJMNCA5LjQwMDAyQzMuNCA5LjkwMDAyIDMuNCAxMC43IDQgMTEuMUwxMSAxNy4yQzExLjYgMTcuNyAxMi40IDE3LjcgMTMgMTcuMkwyMCAxMS4xQzIwLjUgMTAuNiAyMC41IDkuODAwMDIgMjAgOS40MDAwMkwxMyAzLjMwMDAyQzEyLjQgMi45MDAwMiAxMS42IDIuOTAwMDIgMTEgMy40MDAwMloiIGZpbGw9IiMwMDNCN0MiLz48L3N2Zz4=)}.trending_down{color:#4abeff}.trending_up{color:#c20808}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "component", type: DatepickerComponent, selector: "metaqs2-datepicker", inputs: ["disabled", "inputGroup"] }, { kind: "component", type: MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: MatCardContent, selector: "mat-card-content" }, { kind: "component", type: MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "directive", type: MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "component", type: i4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ProgressSpinnerComponent, selector: "metaqs2-progress-spinner", inputs: ["color", "diameter", "strokeWidth", "backdropEnabled", "positionGloballyCenter", "displayProgressSpinner"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
3964
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TreeLicenseComponent, isStandalone: true, selector: "metaqs2-tree-license", inputs: { collectionId: "collectionId", sourceType: "sourceType" }, usesInheritance: true, ngImport: i0, template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title data-test-id=\"page-title\">\n Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{ isLoading() ? \": Lade neue Daten.\" : \"\" }}\n </mat-card-title>\n </mat-card-header>\n <!-- consider to put the filter in the table header to avoid that it is scrolled out of view-->\n <!-- show the filter after the values are loaded to avoid loading current data twice -->\n <mat-card-content class=\"toolbar\">\n <metaqs2-datepicker style=\"display: inline-block\" matRipple [disabled]=\"isLoading() || !isHistoryEnabled()\" [inputGroup]=\"range\" *ngIf=\"timeFilterLoaded() && isHistoryEnabled()\"></metaqs2-datepicker>\n <div style=\"flex: 1 1 auto\"></div>\n <mat-slide-toggle [ngModel]=\"isHistoryEnabled()\" (ngModelChange)=\"isHistoryEnabled.set($event)\" [disabled]=\"isLoading()\">\n <label>Zeige historische Daten</label>\n </mat-slide-toggle>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentTypeCount$.value.rows\"\n class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"label-col\" sticky>\n <th [attr.rowspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef>\n <div>Quelle</div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n [matTooltip]=\"row.meta.alt_label\"\n class=\"label-col mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{ row.meta.label }}\n </td>\n </ng-container>\n <!-- one column for each type -->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_type'\">\n <th [attr.colspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef [matTooltip]=\"col.label\">\n {{ columnTranslationkey ? (columnTranslationkey + col.label | translate) : col.label }}\n </th>\n </ng-container>\n <!-- one column for each type for the most current date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_recent'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef\n matTooltip=\"no tooltip\">{{ range.controls.end.value.toLocaleString(DateTime.DATE_SHORT) }}\n </th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\">\n <a [attr.href]=\"openInEditor(row.meta.id, col.id) | async\" target=\"editor_frontend\">{{ row.counts[col.id] ?? '\u2013' }}</a>\n </td>\n </ng-container>\n <!-- one column for each type for the older date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_past'\">\n <th class=\"past-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"no tooltip\">\n {{ (pastTypeCount$ | async)?.rows?.length ? range.controls.start.value.toLocaleString(DateTime.DATE_SHORT) : 'no past data' }}\n </th>\n <td class=\"past-data-cell\" mat-cell *matCellDef=\"let row;\" >\n <ng-container *ngIf=\"(pastTypeCount$ | async)?.rows?.length && pastTypeCount(row, col.id) as trend\">\n <span [class]=\"trend.trend\"> {{ trend.value ?? '\u2013' }}\n <mat-icon *ngIf=\"trend.value\" aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" /></span>\n <span class=\"cdk-visually-hidden\">{{ trend.trend }}</span>\n </ng-container>\n </td>\n </ng-container>\n <!-- generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['label-col'].concat(typeColumns()); sticky:true;\"></tr>\n <tr [hidden]=\"!isHistoryEnabled()\" mat-header-row *matHeaderRowDef=\"allColumns(); sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['label-col'].concat(allColumns())\"></tr>\n\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}tr:nth-child(2n){background-color:#e4e4e4}tr:nth-child(2n)>td.label-col,tr:nth-child(2n) td.recent-data-cell{border-right:1px solid white}tr:nth-child(odd){background-color:#fff}tr:nth-child(odd)>td.label-col,tr:nth-child(odd) td.recent-data-cell{border-right:1px solid #e4e4e4}td.label-col{text-align:left}.mat-mdc-header-cell,.mat-mdc-cell{text-align:center}.mat-mdc-header-cell a[href],.mat-mdc-cell a[href]{color:var(--mat-table-row-item-label-text-color);cursor:pointer;text-decoration:underline}.mat-mdc-header-cell a[href]:hover,.mat-mdc-cell a[href]:hover{text-decoration:underline}.mat-mdc-header-cell mat-icon,.mat-mdc-cell mat-icon{margin-left:5px;vertical-align:middle}.trending_down{color:#4abeff}.trending_up{color:#c20808}.toolbar,.actionbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:.5rem}\n", ".while-loading{filter:blur(2px)}tr:nth-child(2n),tr:nth-child(odd){background-color:#fff}tr:nth-child(2n)>td.label-col,tr:nth-child(2n) td.recent-data-cell,tr:nth-child(odd)>td.label-col,tr:nth-child(odd) td.recent-data-cell{border-right:1px solid #e4e4e4}.mat-cell-level-1{padding-left:20px!important;text-align:left}.mat-cell-level-1:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-2{padding-left:40px!important;text-align:left}.mat-cell-level-2:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-3{padding-left:60px!important;text-align:left}.mat-cell-level-3:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-4{padding-left:80px!important;text-align:left}.mat-cell-level-4:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-5{padding-left:100px!important;text-align:left}.mat-cell-level-5:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-6{padding-left:120px!important;text-align:left}.mat-cell-level-6:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-7{padding-left:140px!important;text-align:left}.mat-cell-level-7:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-8{padding-left:160px!important;text-align:left}.mat-cell-level-8:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-2:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PHBhdGggb3BhY2l0eT0iMC4zIiBkPSJNMTkgMTAuM0wxMiAxNi4zTDUgMTAuM0wxMiA0LjE5OTk1TDE5IDEwLjNaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+)}.mat-cell-level-0:before,.mat-cell-level-1:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNCAxMi45TDMgMTMuOEwxMSAyMC43QzExLjYgMjEuMiAxMi40IDIxLjIgMTMgMjAuN0wyMSAxMy44TDIwIDEyLjlMMTIgMTkuOEw0IDEyLjlaTTExIDMuNDAwMDJMNCA5LjQwMDAyQzMuNCA5LjkwMDAyIDMuNCAxMC43IDQgMTEuMUwxMSAxNy4yQzExLjYgMTcuNyAxMi40IDE3LjcgMTMgMTcuMkwyMCAxMS4xQzIwLjUgMTAuNiAyMC41IDkuODAwMDIgMjAgOS40MDAwMkwxMyAzLjMwMDAyQzEyLjQgMi45MDAwMiAxMS42IDIuOTAwMDIgMTEgMy40MDAwMloiIGZpbGw9IiMwMDNCN0MiLz48L3N2Zz4=)}.trending_down{color:#4abeff}.trending_up{color:#c20808}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "component", type: DatepickerComponent, selector: "metaqs2-datepicker", inputs: ["disabled", "inputGroup"] }, { kind: "component", type: MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: MatCardContent, selector: "mat-card-content" }, { kind: "component", type: MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "directive", type: MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i5$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i5$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i5$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i5$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i5$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i5$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i5$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "component", type: i5$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i5$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ProgressSpinnerComponent, selector: "metaqs2-progress-spinner", inputs: ["color", "diameter", "strokeWidth", "backdropEnabled", "positionGloballyCenter", "displayProgressSpinner"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
3920
3965
  }
3921
3966
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeLicenseComponent, decorators: [{
3922
3967
  type: Component,
@@ -3946,16 +3991,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3946
3991
  ProgressSpinnerComponent,
3947
3992
  TranslateModule,
3948
3993
  FormsModule,
3949
- ], template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title data-test-id=\"page-title\">\n Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{ isLoading() ? \": Lade neue Daten.\" : \"\" }}\n </mat-card-title>\n </mat-card-header>\n <!-- consider to put the filter in the table header to avoid that it is scrolled out of view-->\n <!-- show the filter after the values are loaded to avoid loading current data twice -->\n <mat-card-content class=\"toolbar\">\n <div style=\"flex: 1 1 auto\"></div>\n <metaqs2-datepicker style=\"display: inline-block\" matRipple #datepickerRipple=\"matRipple\" [disabled]=\"isLoading() || !isHistoryEnabled()\" [inputGroup]=\"range\" *ngIf=\"timeFilterLoaded() && isHistoryEnabled()\"></metaqs2-datepicker>\n <mat-slide-toggle [ngModel]=\"isHistoryEnabled()\" (ngModelChange)=\"isHistoryEnabled.set($event)\" [disabled]=\"isLoading()\" *ngIf=\"timeFilterLoaded()\">\n <label>Zeige historische Daten</label>\n </mat-slide-toggle>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentTypeCount$.value.rows\"\n class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"label-col\" sticky>\n <th [attr.rowspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef>\n <div>Quelle</div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n [matTooltip]=\"row.meta.alt_label\"\n class=\"label-col mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{ row.meta.label }}\n </td>\n </ng-container>\n <!-- one column for each type -->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_type'\">\n <th [attr.colspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef [matTooltip]=\"col.label\">\n {{ columnTranslationkey ? (columnTranslationkey + col.label | translate) : col.label }}\n </th>\n </ng-container>\n <!-- one column for each type for the most current date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_recent'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef\n matTooltip=\"no tooltip\">{{ range.controls.end.value.toLocaleString(DateTime.DATE_SHORT) }}\n </th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\">\n <a [attr.href]=\"openInEditor(row.meta.id, col.id) | async\" target=\"editor_frontend\">{{ row.counts[col.id] ?? '\u2013' }}</a>\n </td>\n </ng-container>\n <!-- one column for each type for the older date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_past'\">\n <th class=\"past-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"no tooltip\">\n {{ (pastTypeCount$ | async)?.rows?.length ? range.controls.start.value.toLocaleString(DateTime.DATE_SHORT) : 'no past data' }}\n </th>\n <td class=\"past-data-cell\" mat-cell *matCellDef=\"let row;\" >\n <ng-container *ngIf=\"(pastTypeCount$ | async)?.rows?.length && pastTypeCount(row, col.id) as trend\">\n <span [class]=\"trend.trend\"> {{ trend.value ?? '\u2013' }}\n <mat-icon *ngIf=\"trend.value\" aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" /></span>\n <span class=\"cdk-visually-hidden\">{{ trend.trend }}</span>\n </ng-container>\n </td>\n </ng-container>\n <!-- generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['label-col'].concat(typeColumns()); sticky:true;\"></tr>\n <tr [hidden]=\"!isHistoryEnabled()\" mat-header-row *matHeaderRowDef=\"allColumns(); sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['label-col'].concat(allColumns())\"></tr>\n\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}.mat-cell-level-1{padding-left:20px!important;text-align:left}.mat-cell-level-1:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-2{padding-left:40px!important;text-align:left}.mat-cell-level-2:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-3{padding-left:60px!important;text-align:left}.mat-cell-level-3:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-4{padding-left:80px!important;text-align:left}.mat-cell-level-4:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-5{padding-left:100px!important;text-align:left}.mat-cell-level-5:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-6{padding-left:120px!important;text-align:left}.mat-cell-level-6:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-7{padding-left:140px!important;text-align:left}.mat-cell-level-7:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-8{padding-left:160px!important;text-align:left}.mat-cell-level-8:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-2:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PHBhdGggb3BhY2l0eT0iMC4zIiBkPSJNMTkgMTAuM0wxMiAxNi4zTDUgMTAuM0wxMiA0LjE5OTk1TDE5IDEwLjNaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+)}.mat-cell-level-0:before,.mat-cell-level-1:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNCAxMi45TDMgMTMuOEwxMSAyMC43QzExLjYgMjEuMiAxMi40IDIxLjIgMTMgMjAuN0wyMSAxMy44TDIwIDEyLjlMMTIgMTkuOEw0IDEyLjlaTTExIDMuNDAwMDJMNCA5LjQwMDAyQzMuNCA5LjkwMDAyIDMuNCAxMC43IDQgMTEuMUwxMSAxNy4yQzExLjYgMTcuNyAxMi40IDE3LjcgMTMgMTcuMkwyMCAxMS4xQzIwLjUgMTAuNiAyMC41IDkuODAwMDIgMjAgOS40MDAwMkwxMyAzLjMwMDAyQzEyLjQgMi45MDAwMiAxMS42IDIuOTAwMDIgMTEgMy40MDAwMloiIGZpbGw9IiMwMDNCN0MiLz48L3N2Zz4=)}.trending_down{color:#4abeff}.trending_up{color:#c20808}\n"] }]
3994
+ ], template: "<mat-card appearance=\"raised\">\n <mat-card-header *ngIf=\"pageTitle\">\n <mat-card-title data-test-id=\"page-title\">\n Qualit\u00E4tsmetrik: {{ pageTitle | translate }}{{ isLoading() ? \": Lade neue Daten.\" : \"\" }}\n </mat-card-title>\n </mat-card-header>\n <!-- consider to put the filter in the table header to avoid that it is scrolled out of view-->\n <!-- show the filter after the values are loaded to avoid loading current data twice -->\n <mat-card-content class=\"toolbar\">\n <metaqs2-datepicker style=\"display: inline-block\" matRipple [disabled]=\"isLoading() || !isHistoryEnabled()\" [inputGroup]=\"range\" *ngIf=\"timeFilterLoaded() && isHistoryEnabled()\"></metaqs2-datepicker>\n <div style=\"flex: 1 1 auto\"></div>\n <mat-slide-toggle [ngModel]=\"isHistoryEnabled()\" (ngModelChange)=\"isHistoryEnabled.set($event)\" [disabled]=\"isLoading()\">\n <label>Zeige historische Daten</label>\n </mat-slide-toggle>\n </mat-card-content>\n</mat-card>\n<mat-card>\n <metaqs2-progress-spinner [displayProgressSpinner]=\"isLoading()\"></metaqs2-progress-spinner>\n <table [class.while-loading]=\"isLoading()\" mat-table [dataSource]=\"recentTypeCount$.value.rows\"\n class=\"quality-matrix\">\n <!-- Define columns of table -->\n <!-- Row Header Column -->\n <ng-container matColumnDef=\"label-col\" sticky>\n <th [attr.rowspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef>\n <div>Quelle</div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n [matTooltip]=\"row.meta.alt_label\"\n class=\"label-col mat-cell-level-{{row.meta.level + 1}}\"\n >\n {{ row.meta.label }}\n </td>\n </ng-container>\n <!-- one column for each type -->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_type'\">\n <th [attr.colspan]=\"isHistoryEnabled() ? '2' : '1'\" mat-header-cell *matHeaderCellDef [matTooltip]=\"col.label\">\n {{ columnTranslationkey ? (columnTranslationkey + col.label | translate) : col.label }}\n </th>\n </ng-container>\n <!-- one column for each type for the most current date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_recent'\">\n <th class=\"recent-data-cell\" mat-header-cell *matHeaderCellDef\n matTooltip=\"no tooltip\">{{ range.controls.end.value.toLocaleString(DateTime.DATE_SHORT) }}\n </th>\n <td class=\"recent-data-cell\" mat-cell *matCellDef=\"let row\">\n <a [attr.href]=\"openInEditor(row.meta.id, col.id) | async\" target=\"editor_frontend\">{{ row.counts[col.id] ?? '\u2013' }}</a>\n </td>\n </ng-container>\n <!-- one column for each type for the older date-->\n <ng-container *ngFor=\"let col of (recentTypeCount$ | async)?.columns; trackBy:columnIdent\"\n [matColumnDef]=\"col.id + '_past'\">\n <th class=\"past-data-cell\" mat-header-cell *matHeaderCellDef matTooltip=\"no tooltip\">\n {{ (pastTypeCount$ | async)?.rows?.length ? range.controls.start.value.toLocaleString(DateTime.DATE_SHORT) : 'no past data' }}\n </th>\n <td class=\"past-data-cell\" mat-cell *matCellDef=\"let row;\" >\n <ng-container *ngIf=\"(pastTypeCount$ | async)?.rows?.length && pastTypeCount(row, col.id) as trend\">\n <span [class]=\"trend.trend\"> {{ trend.value ?? '\u2013' }}\n <mat-icon *ngIf=\"trend.value\" aria-hidden=\"false\" [attr.aria-label]=\"trend.trend\" [fontIcon]=\"trend.trend!\" /></span>\n <span class=\"cdk-visually-hidden\">{{ trend.trend }}</span>\n </ng-container>\n </td>\n </ng-container>\n <!-- generate actual table -->\n <tr mat-header-row *matHeaderRowDef=\"['label-col'].concat(typeColumns()); sticky:true;\"></tr>\n <tr [hidden]=\"!isHistoryEnabled()\" mat-header-row *matHeaderRowDef=\"allColumns(); sticky: true;\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['label-col'].concat(allColumns())\"></tr>\n\n </table>\n</mat-card>\n", styles: [".while-loading{filter:blur(2px)}tr:nth-child(2n){background-color:#e4e4e4}tr:nth-child(2n)>td.label-col,tr:nth-child(2n) td.recent-data-cell{border-right:1px solid white}tr:nth-child(odd){background-color:#fff}tr:nth-child(odd)>td.label-col,tr:nth-child(odd) td.recent-data-cell{border-right:1px solid #e4e4e4}td.label-col{text-align:left}.mat-mdc-header-cell,.mat-mdc-cell{text-align:center}.mat-mdc-header-cell a[href],.mat-mdc-cell a[href]{color:var(--mat-table-row-item-label-text-color);cursor:pointer;text-decoration:underline}.mat-mdc-header-cell a[href]:hover,.mat-mdc-cell a[href]:hover{text-decoration:underline}.mat-mdc-header-cell mat-icon,.mat-mdc-cell mat-icon{margin-left:5px;vertical-align:middle}.trending_down{color:#4abeff}.trending_up{color:#c20808}.toolbar,.actionbar{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:.5rem}\n", ".while-loading{filter:blur(2px)}tr:nth-child(2n),tr:nth-child(odd){background-color:#fff}tr:nth-child(2n)>td.label-col,tr:nth-child(2n) td.recent-data-cell,tr:nth-child(odd)>td.label-col,tr:nth-child(odd) td.recent-data-cell{border-right:1px solid #e4e4e4}.mat-cell-level-1{padding-left:20px!important;text-align:left}.mat-cell-level-1:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-2{padding-left:40px!important;text-align:left}.mat-cell-level-2:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-3{padding-left:60px!important;text-align:left}.mat-cell-level-3:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-4{padding-left:80px!important;text-align:left}.mat-cell-level-4:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-5{padding-left:100px!important;text-align:left}.mat-cell-level-5:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-6{padding-left:120px!important;text-align:left}.mat-cell-level-6:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-7{padding-left:140px!important;text-align:left}.mat-cell-level-7:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-8{padding-left:160px!important;text-align:left}.mat-cell-level-8:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+);padding-right:5px}.mat-cell-level-2:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAuMyA5LjkwMDA1QzIwLjIgOS43MDAwNSAyMC4xIDkuNjAwMDUgMjAgOS40MDAwNUwxMyAzLjMwMDA1QzEyLjUgMi44MDAwNSAxMS41IDIuODAwMDUgMTEgMy4zMDAwNUw0IDkuNDAwMDVDMy41IDkuOTAwMDUgMy41IDEwLjcgNCAxMS4xTDExIDE3LjJDMTEuNSAxNy43IDEyLjUgMTcuNyAxMyAxNy4yTDIwIDExLjFDMjAuMyAxMC44IDIwLjQgMTAuNSAyMC40IDEwLjJDMjAuNCAxMC4xIDIwLjQgMTAgMjAuMyA5LjkwMDA1Wk01IDEwLjNMMTIgNC4yMDAwNUwxOSAxMC4zTDEyIDE2LjRMNSAxMC4zWk0yMCAxMi45TDEyIDE5LjhMNCAxMi45TDMgMTMuOEwxMSAyMC43MDAxQzExLjUgMjEuMjAwMSAxMi41IDIxLjIwMDEgMTMgMjAuNzAwMUwyMSAxMy44TDIwIDEyLjlaIiBmaWxsPSIjMDAzQjdDIi8+PHBhdGggb3BhY2l0eT0iMC4zIiBkPSJNMTkgMTAuM0wxMiAxNi4zTDUgMTAuM0wxMiA0LjE5OTk1TDE5IDEwLjNaIiBmaWxsPSIjMDAzQjdDIi8+PC9zdmc+)}.mat-cell-level-0:before,.mat-cell-level-1:before{content:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNCAxMi45TDMgMTMuOEwxMSAyMC43QzExLjYgMjEuMiAxMi40IDIxLjIgMTMgMjAuN0wyMSAxMy44TDIwIDEyLjlMMTIgMTkuOEw0IDEyLjlaTTExIDMuNDAwMDJMNCA5LjQwMDAyQzMuNCA5LjkwMDAyIDMuNCAxMC43IDQgMTEuMUwxMSAxNy4yQzExLjYgMTcuNyAxMi40IDE3LjcgMTMgMTcuMkwyMCAxMS4xQzIwLjUgMTAuNiAyMC41IDkuODAwMDIgMjAgOS40MDAwMkwxMyAzLjMwMDAyQzEyLjQgMi45MDAwMiAxMS42IDIuOTAwMDIgMTEgMy40MDAwMloiIGZpbGw9IiMwMDNCN0MiLz48L3N2Zz4=)}.trending_down{color:#4abeff}.trending_up{color:#c20808}\n"] }]
3950
3995
  }], propDecorators: { collectionId: [{
3951
3996
  type: Input,
3952
3997
  args: [{ required: true }]
3953
3998
  }], sourceType: [{
3954
3999
  type: Input,
3955
4000
  args: [{ required: false }]
3956
- }], apiMethod: [{
3957
- type: Input,
3958
- args: [{ required: false }]
3959
4001
  }] } });
3960
4002
 
3961
4003
  /*
@@ -3966,5 +4008,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3966
4008
  * Generated bundle index. Do not edit.
3967
4009
  */
3968
4010
 
3969
- export { CollectionCountHistoryComponent, CollectionIssuesComponent, ConfigHelperService, CountsWithHistoryComponent, DonutChartTooltipComponent, MaterialIssuesComponent, NG_META_WIDGETS_LIB_CONFIGURATION, NgMetaWidgetsLibConfiguration, NgMetaWidgetsLibModule, NodeListComponent, QualityMatrixComponent, TOOLTIP_DATA, TOOLTIP_REF, TooltipRefImpl, TooltipService, TreeCollectionDetailsComponent, TreeLicenseComponent, TreeSearchCountsComponent, borderPositionStrategy, centerPositionStrategy, createRegister, transformDonutChartData };
4011
+ export { BaseHistoricDataTableDirective, CollectionCountHistoryComponent, CollectionIssuesComponent, ConfigHelperService, CountsWithHistoryComponent, DonutChartTooltipComponent, MaterialIssuesComponent, NG_META_WIDGETS_LIB_CONFIGURATION, NgMetaWidgetsLibConfiguration, NgMetaWidgetsLibModule, NodeListComponent, QualityMatrixComponent, TOOLTIP_DATA, TOOLTIP_REF, TooltipRefImpl, TooltipService, TreeCollectionDetailsComponent, TreeLicenseComponent, TreeSearchCountsComponent, borderPositionStrategy, centerPositionStrategy, createRegister, transformDonutChartData };
3970
4012
  //# sourceMappingURL=ngx-edu-sharing-metaqs2.mjs.map