@universis/ngx-tables 0.8.0 → 0.8.2

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.
@@ -3,16 +3,17 @@ import * as jQuery_ from 'jquery';
3
3
  import 'datatables.net';
4
4
  import 'datatables.net-scroller';
5
5
  import 'datatables.net-colreorder';
6
+ import 'datatables.net-buttons';
6
7
  import 'rxjs/add/observable/combineLatest';
7
8
  import { HttpClient } from '@angular/common/http';
8
- import { ClientDataQueryable, ResponseError, TextUtils } from '@themost/client';
9
+ import { ResponseError, ClientDataQueryable, TextUtils } from '@themost/client';
9
10
  import { BehaviorSubject } from 'rxjs';
10
11
  import { AngularDataContext } from '@themost/angular';
11
12
  import { __awaiter } from 'tslib';
12
13
  import { DatePipe, CommonModule } from '@angular/common';
13
14
  import { TranslateService, TranslatePipe, TranslateModule } from '@ngx-translate/core';
14
15
  import { FormControl, FormArray, FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
15
- import { TemplatePipe, ModalService, LoadingService, ErrorService, DIALOG_BUTTONS, UserActivityService, ToastService, AppEventService, UserStorageService, ConfigurationService, SharedModule } from '@universis/common';
16
+ import { TemplatePipe, ModalService, ConfigurationService, ErrorService, LoadingService, DIALOG_BUTTONS, ExportSpreadsheetService, UserActivityService, ToastService, AppEventService, UserStorageService, SharedModule } from '@universis/common';
16
17
  import { RouterModalOkCancel, RouterModalModule } from '@universis/common/routing';
17
18
  import { ServiceUrlPreProcessor, TranslatePreProcessor, AdvancedFormsModule } from '@universis/forms';
18
19
  import { FormioModule } from 'angular-formio';
@@ -20,10 +21,10 @@ import { BsModalRef, BsModalService, ModalModule } from 'ngx-bootstrap/modal';
20
21
  import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
21
22
  import { GroupByPipe, NgPipesModule } from 'ngx-pipes';
22
23
  import { template, at, cloneDeep } from 'lodash';
23
- import { Injectable, Directive, Optional, Input, Output, EventEmitter, Pipe, Component, ViewChild, ViewEncapsulation, ElementRef, ChangeDetectorRef, Inject, InjectionToken, Injector, NgModule, CUSTOM_ELEMENTS_SCHEMA, defineInjectable, inject, HostListener, ChangeDetectionStrategy } from '@angular/core';
24
+ import { Injectable, Directive, Optional, Input, Output, EventEmitter, Pipe, Component, ViewChild, ViewEncapsulation, ElementRef, ChangeDetectorRef, NgModule, CUSTOM_ELEMENTS_SCHEMA, defineInjectable, inject, HostListener, InjectionToken, Inject, Injector, ChangeDetectionStrategy } from '@angular/core';
24
25
  import { ActivatedRoute, Router, NavigationStart, NavigationEnd, RouterModule } from '@angular/router';
25
26
  import { createFeatureSelector, createSelector, select, Store } from '@ngrx/store';
26
- import { first, filter } from 'rxjs/operators';
27
+ import { skip, first, filter } from 'rxjs/operators';
27
28
 
28
29
  class AdvancedColumnFormatter {
29
30
  static template(expr) {
@@ -704,6 +705,270 @@ ColumnSelectorService.ctorParameters = () => [
704
705
  { type: ModalService }
705
706
  ];
706
707
 
708
+ class ActivatedTableService {
709
+ constructor(_router, _activatedRoute) {
710
+ this._router = _router;
711
+ this._activatedRoute = _activatedRoute;
712
+ /**
713
+ * Get the last table that was set as active
714
+ * Note: Emitted value may be null (e.g. reset on route changes)
715
+ */
716
+ this.lastActiveTable = new BehaviorSubject(null);
717
+ /**
718
+ * Omit the last emitted value to observe only new active table changes
719
+ * Note: Emitted value may be null (e.g. reset on route changes)
720
+ */
721
+ this.nextActiveTable = this.lastActiveTable.pipe(skip(1));
722
+ _router.events.forEach((event) => {
723
+ if (event instanceof NavigationStart) {
724
+ if (this._activeTable) {
725
+ this.activeTable = null;
726
+ }
727
+ }
728
+ });
729
+ }
730
+ get activeTable() {
731
+ return this._activeTable;
732
+ }
733
+ set activeTable(tableComponent) {
734
+ this._activeTable = tableComponent;
735
+ // provide change to observers
736
+ this.lastActiveTable.next(this._activeTable);
737
+ }
738
+ }
739
+ ActivatedTableService.decorators = [
740
+ { type: Injectable, args: [{
741
+ providedIn: 'root'
742
+ },] }
743
+ ];
744
+ /** @nocollapse */
745
+ ActivatedTableService.ctorParameters = () => [
746
+ { type: Router },
747
+ { type: ActivatedRoute }
748
+ ];
749
+ ActivatedTableService.ngInjectableDef = defineInjectable({ factory: function ActivatedTableService_Factory() { return new ActivatedTableService(inject(Router), inject(ActivatedRoute)); }, token: ActivatedTableService, providedIn: "root" });
750
+
751
+ const MAX_EXPORT_ITEMS = 500;
752
+ class BtnExpDirective {
753
+ constructor(_activatedTable, _context, _config, _translate, _loadingService, _errorService) {
754
+ this._activatedTable = _activatedTable;
755
+ this._context = _context;
756
+ this._config = _config;
757
+ this._translate = _translate;
758
+ this._loadingService = _loadingService;
759
+ this._errorService = _errorService;
760
+ }
761
+ clickEvent(event) {
762
+ return __awaiter(this, void 0, void 0, function* () {
763
+ event.preventDefault();
764
+ event.stopPropagation();
765
+ if (this._activatedTable.activeTable) {
766
+ return this._activatedTable.activeTable.exportView();
767
+ /*
768
+ const lastQuery = this._activatedTable.activeTable.lastQuery;
769
+ const tableConfig = this._activatedTable.activeTable.config;
770
+ const serviceHeaders = this._context.getService().getHeaders();
771
+ const queryModel = lastQuery.getModel();
772
+ let query = this._context.model(queryModel).asQueryable();
773
+ const queryParams = lastQuery.getParams();
774
+ query = this.constructQuery(query, queryParams, tableConfig, serviceHeaders);
775
+ // get export settings
776
+ const exportSettings = this._config.settings as ExportLimitConfiguration;
777
+ // get export limit
778
+ const maxExportItems = exportSettings && exportSettings.tables && exportSettings.tables.exportLimit;
779
+ if (maxExportItems && typeof maxExportItems === 'number' && maxExportItems > 0) {
780
+ query.skip(0).take(maxExportItems);
781
+ } else {
782
+ query.skip(0).take(MAX_EXPORT_ITEMS);
783
+ }
784
+ // This constructs the URI based on the way @themost does
785
+ const url = this.constructURL(query);
786
+ this.downloadFile(url, query.getService().getHeaders(), query.getModel()); */
787
+ }
788
+ });
789
+ }
790
+ /**
791
+ * Sets the parameters to the query based on
792
+ * the active filters of the activated table
793
+ * @param {ClientDataQueryable} query
794
+ * @param params: The filters of the last query of the activated table
795
+ * @return ClientDataQueryable
796
+ */
797
+ setParams(query, params) {
798
+ if (params && typeof params === 'object') {
799
+ Object.keys(params).forEach((key) => {
800
+ query.setParam(key, params[key]);
801
+ });
802
+ }
803
+ return query;
804
+ }
805
+ /**
806
+ * Sets the headers to the query based on
807
+ * the default headers of the DataContext
808
+ * and appending the accept header to get
809
+ * an xlsx file from the API
810
+ * @param {ClientDataQueryable} query
811
+ * @param {Headers} headers: The headers to append to the query
812
+ * @return ClientDataQueryable
813
+ */
814
+ setHeaders(query, headers) {
815
+ Object.keys(headers).forEach((key) => {
816
+ if (headers.hasOwnProperty(key)) {
817
+ query.getService().setHeader(key, headers[key]);
818
+ }
819
+ });
820
+ // sets a header to accept xlsx files
821
+ query.getService().setHeader('Accept', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
822
+ return query;
823
+ }
824
+ /**
825
+ * Constructs the select parameter of the
826
+ * ClientDataQuery by replacing the target name
827
+ * of the field based on the localized translation
828
+ * of that property on the advanced tabled
829
+ * @param {ClientDataQueryable} query
830
+ * @param tableConfig: The configuration of the activated table
831
+ * @return ClientDataQueryable
832
+ */
833
+ constructQueryParam(query, tableConfig) {
834
+ let selectQuery = query.getParams().$select;
835
+ let selectQueryArray = selectQuery.split(',');
836
+ selectQueryArray = selectQueryArray.map((select$$1) => {
837
+ const words = select$$1.split(' ');
838
+ if (words.length === 3) {
839
+ if (tableConfig && tableConfig.columns) {
840
+ for (const column of tableConfig.columns) {
841
+ if (column.property === words[2] && column.title) {
842
+ words[2] = `"${this._translate.instant(column.title)}"`;
843
+ }
844
+ else if (column.property === words[2]) {
845
+ words[2] = `"${this._translate.instant(words[2])}"`;
846
+ }
847
+ }
848
+ }
849
+ }
850
+ if (words.length === 1) {
851
+ if (tableConfig && tableConfig.columns) {
852
+ for (const column of tableConfig.columns) {
853
+ if (column.name === words[0] && column.title) {
854
+ words[0] = `${words[0]} as "${this._translate.instant(column.title)}"`;
855
+ break;
856
+ }
857
+ else if (column.name === words[0] && column.property) {
858
+ words[0] = `${words[0]} as "${this._translate.instant(column.property)}"`;
859
+ break;
860
+ }
861
+ else if (words[0] === column.name && words[0] === "id" && column.hidden) {
862
+ break;
863
+ }
864
+ else if (words[0] == column.name || words[0] === column.property) {
865
+ words[0] = `${words[0]} as "${this._translate.instant(words[0])}"`;
866
+ }
867
+ }
868
+ }
869
+ return words[0];
870
+ }
871
+ return words.join(' ');
872
+ });
873
+ selectQuery = selectQueryArray.join(',');
874
+ query.setParam('$select', selectQuery);
875
+ return query;
876
+ }
877
+ /**
878
+ * Constructs the fetch URL based the query parameters
879
+ * @param {ClientDataQueryable} query
880
+ * @return String
881
+ */
882
+ constructURL(query) {
883
+ const baseURL = query.getService().getBase();
884
+ let url = baseURL.endsWith('/') ? (baseURL + query.getModel() + '?') : (baseURL + '/' + query.getModel() + '?');
885
+ Object.keys(query.getParams()).forEach((key, index) => {
886
+ if (index === 0) {
887
+ url += key + '=' + query.getParams()[key];
888
+ }
889
+ else {
890
+ url += '&' + key + '=' + query.getParams()[key];
891
+ }
892
+ });
893
+ return url;
894
+ }
895
+ /**
896
+ * Constructs the query by setting the parameters of the
897
+ * advanced table's active filters, sets the necessary headers
898
+ * and build the select parameter of the query
899
+ * @param {ClientDataQueryable} query
900
+ * @param params: The filters of the last query of the activated table
901
+ * @param tableConfig: The configuration of the activated table
902
+ * @param {Headers} headers: The headers to append to the query
903
+ * @return ClientDataQueryable
904
+ */
905
+ constructQuery(query, params, tableConfig, headers) {
906
+ let _query = this.setParams(query, params);
907
+ _query = this.setHeaders(_query, headers);
908
+ _query = this.constructQueryParam(_query, tableConfig);
909
+ return _query;
910
+ }
911
+ /**
912
+ * Fetches and saves the xlsx file
913
+ * @param {String} url
914
+ * @param {Headers} serviceHeaders: The headers to append to the query
915
+ * @param modelName: The model name of the advanced table
916
+ */
917
+ downloadFile(url, serviceHeaders, modelName) {
918
+ this._loadingService.showLoading();
919
+ fetch(encodeURI(url), {
920
+ headers: serviceHeaders,
921
+ credentials: 'include'
922
+ }).then(response => {
923
+ if (response && !response.ok) {
924
+ throw new ResponseError(response.statusText, response.status);
925
+ }
926
+ return response.blob();
927
+ }).then(blob => {
928
+ const objectUrl = window.URL.createObjectURL(blob);
929
+ const a = document.createElement('a');
930
+ document.body.appendChild(a);
931
+ a.setAttribute('style', 'display: none');
932
+ a.href = objectUrl;
933
+ const downloadName = `${modelName}.xlsx`;
934
+ a.download = downloadName;
935
+ // this adds support for IE and MS Edge (up to version 44.19041)
936
+ if (window.navigator && window.navigator.msSaveOrOpenBlob) {
937
+ window.navigator.msSaveOrOpenBlob(blob, downloadName);
938
+ }
939
+ else {
940
+ // for all other browsers
941
+ a.click();
942
+ }
943
+ window.URL.revokeObjectURL(objectUrl);
944
+ a.remove();
945
+ this._loadingService.hideLoading();
946
+ }).catch(err => {
947
+ this._loadingService.hideLoading();
948
+ this._errorService.showError(err, {
949
+ continueLink: '.'
950
+ });
951
+ });
952
+ }
953
+ }
954
+ BtnExpDirective.decorators = [
955
+ { type: Directive, args: [{
956
+ selector: '.universis-btn-export'
957
+ },] }
958
+ ];
959
+ /** @nocollapse */
960
+ BtnExpDirective.ctorParameters = () => [
961
+ { type: ActivatedTableService },
962
+ { type: AngularDataContext },
963
+ { type: ConfigurationService },
964
+ { type: TranslateService },
965
+ { type: LoadingService },
966
+ { type: ErrorService }
967
+ ];
968
+ BtnExpDirective.propDecorators = {
969
+ clickEvent: [{ type: HostListener, args: ['click', ['$event'],] }]
970
+ };
971
+
707
972
  // restore jquery import to avoid Cannot call a namespace ('jquery') error
708
973
  const jQuery = jQuery_;
709
974
  const DataTablesApi = jQuery.fn.dataTable.Api;
@@ -731,6 +996,12 @@ class TableTranslationChangeDetector extends ChangeDetectorRef {
731
996
  }
732
997
  }
733
998
  let COLUMN_FORMATTERS = new InjectionToken('column.formatters');
999
+ class ExportLimitExceededError extends RangeError {
1000
+ constructor(message) {
1001
+ super(message);
1002
+ this.name = 'ExportLimitExceededError';
1003
+ }
1004
+ }
734
1005
  class ColumnFormatter extends AdvancedColumnFormatter {
735
1006
  constructor(injector) {
736
1007
  super();
@@ -755,7 +1026,7 @@ function getRandomIdentifier() {
755
1026
  return (Number(String(Math.random()).slice(2))).toString(36);
756
1027
  }
757
1028
  class AdvancedTableComponent {
758
- constructor(_context, _columnFormatters, _activatedRoute, _translateService, _injector, _advancedFilterValueProvider, _element, _template, _loading, _http, _columnSelector) {
1029
+ constructor(_context, _columnFormatters, _activatedRoute, _translateService, _injector, _advancedFilterValueProvider, _element, _template, _loading, _http, _columnSelector, _configuration, _exportSpreadsheet, _modalService, _errorService) {
759
1030
  this._context = _context;
760
1031
  this._columnFormatters = _columnFormatters;
761
1032
  this._activatedRoute = _activatedRoute;
@@ -767,6 +1038,10 @@ class AdvancedTableComponent {
767
1038
  this._loading = _loading;
768
1039
  this._http = _http;
769
1040
  this._columnSelector = _columnSelector;
1041
+ this._configuration = _configuration;
1042
+ this._exportSpreadsheet = _exportSpreadsheet;
1043
+ this._modalService = _modalService;
1044
+ this._errorService = _errorService;
770
1045
  this._firstLoad = true;
771
1046
  this._showFooter = false;
772
1047
  this._showHeader = true;
@@ -810,6 +1085,7 @@ class AdvancedTableComponent {
810
1085
  this.customSelect = false;
811
1086
  this.selected = [];
812
1087
  this.unselected = [];
1088
+ this._lastQueryTotalItems = 0;
813
1089
  // initialize translate pipe
814
1090
  this.translator = new TranslatePipe(this._translateService, new TableTranslationChangeDetector());
815
1091
  jQuery.fn.dataTable.ext.classes.sPageButton = 'btn';
@@ -829,6 +1105,9 @@ class AdvancedTableComponent {
829
1105
  get config() {
830
1106
  return this._config;
831
1107
  }
1108
+ get lastQueryTotalItems() {
1109
+ return this._lastQueryTotalItems;
1110
+ }
832
1111
  /**
833
1112
  * Indicates whether table footer will be visible or not
834
1113
  */
@@ -1437,6 +1716,7 @@ class AdvancedTableComponent {
1437
1716
  recordsFiltered: 0,
1438
1717
  data: [],
1439
1718
  };
1719
+ self._lastQueryTotalItems = 0;
1440
1720
  // emit empty data
1441
1721
  self.load.emit(emptyDataSet);
1442
1722
  // return empty data
@@ -1452,7 +1732,7 @@ class AdvancedTableComponent {
1452
1732
  // get order expression
1453
1733
  const order = aoData[2].value;
1454
1734
  // get skip records param
1455
- let skip = aoData[3].value;
1735
+ let skip$$1 = aoData[3].value;
1456
1736
  // get page size param
1457
1737
  let top = aoData[4].value;
1458
1738
  // get search value
@@ -1461,7 +1741,7 @@ class AdvancedTableComponent {
1461
1741
  const q = self._query instanceof ClientDataQueryable ? self._query : self._context.model(self.config.model).asQueryable();
1462
1742
  // apply paging params
1463
1743
  if (top) {
1464
- q.take(top).skip(skip);
1744
+ q.take(top).skip(skip$$1);
1465
1745
  }
1466
1746
  // apply order params
1467
1747
  if (order && order.length) {
@@ -1531,6 +1811,7 @@ class AdvancedTableComponent {
1531
1811
  recordsFiltered: items.total,
1532
1812
  data: items.value,
1533
1813
  };
1814
+ self._lastQueryTotalItems = items.total;
1534
1815
  if (items.total === 0) {
1535
1816
  self.resetEmptyTable();
1536
1817
  }
@@ -1544,6 +1825,7 @@ class AdvancedTableComponent {
1544
1825
  console.error('TABLES', err);
1545
1826
  // show error
1546
1827
  self.toggleError(err);
1828
+ self._lastQueryTotalItems = 0;
1547
1829
  // by returning empty dataset
1548
1830
  self.load.emit(EMPTY_DATASET);
1549
1831
  return fnCallback(EMPTY_DATASET);
@@ -1556,6 +1838,7 @@ class AdvancedTableComponent {
1556
1838
  recordsFiltered: items.total,
1557
1839
  data: items.value,
1558
1840
  };
1841
+ self._lastQueryTotalItems = items.total;
1559
1842
  if (items.total === 0) {
1560
1843
  self.resetEmptyTable();
1561
1844
  }
@@ -1931,6 +2214,125 @@ class AdvancedTableComponent {
1931
2214
  }
1932
2215
  });
1933
2216
  }
2217
+ /**
2218
+ *
2219
+ * @param options to pass an errorHandler callback, if desired
2220
+ * @returns void
2221
+ */
2222
+ exportView(options) {
2223
+ return __awaiter(this, void 0, void 0, function* () {
2224
+ try {
2225
+ this._loading.showLoading();
2226
+ // validate query items and config
2227
+ if (!(this._lastQueryTotalItems && this.config)) {
2228
+ // do nothing
2229
+ return;
2230
+ }
2231
+ // get export settings
2232
+ const exportSettings = this._configuration.settings;
2233
+ // and export limit
2234
+ const exportLimit = (exportSettings && exportSettings.tables && exportSettings.tables.exportLimit > 0)
2235
+ ? exportSettings.tables.exportLimit : MAX_EXPORT_ITEMS;
2236
+ // and validate it
2237
+ if (this._lastQueryTotalItems > exportLimit) {
2238
+ // call error handler
2239
+ // provide a recognizible error type
2240
+ if (options && options.errorHandler) {
2241
+ options.errorHandler(new ExportLimitExceededError('Export limit exceeded'));
2242
+ return;
2243
+ }
2244
+ // or show warning modal and exit
2245
+ this._modalService.showWarningDialog(this._translateService.instant('Tables.ExportList'), this._translateService.instant('Tables.ExportLimitExceeded', { dataLength: this._lastQueryTotalItems, exportLimit }), DIALOG_BUTTONS.Ok);
2246
+ return;
2247
+ }
2248
+ // get total displayed items
2249
+ const totalDisplayedItems = Array.from(this.dataTable.context[0].aiDisplay).length;
2250
+ // if they already satisfy the last query total
2251
+ if (totalDisplayedItems === this._lastQueryTotalItems) {
2252
+ // prepare excel data immediately
2253
+ const { body, header } = this.getExportableData();
2254
+ // and export them to excel
2255
+ this._exportSpreadsheet.export(body, `${this._translateService.instant(this.config.title || 'Tables.ExportResults')}.xlsx`, {
2256
+ header,
2257
+ skipHeader: false
2258
+ });
2259
+ }
2260
+ else {
2261
+ // at this point, more data need to be fetched
2262
+ // hold previous data state
2263
+ const previousDataState = this.dataTable.rows().data().toArray();
2264
+ // get target data state by executing the last query
2265
+ // note: taking the exportLimit amount of items will always satisfy the results,
2266
+ // because it has been validated
2267
+ const targetDataState = yield this.lastQuery.take(exportLimit).getItems();
2268
+ // change table data on the fly, but do not redraw
2269
+ this.dataTable.clear().rows.add(targetDataState);
2270
+ // prepare excel data
2271
+ const { body, header } = this.getExportableData();
2272
+ // reset table data
2273
+ this.dataTable.clear().rows.add(previousDataState);
2274
+ // and export target data to excel
2275
+ this._exportSpreadsheet.export(body, `${this._translateService.instant(this.config.title || 'Tables.ExportResults')}.xlsx`, {
2276
+ header,
2277
+ skipHeader: false
2278
+ });
2279
+ }
2280
+ // exit
2281
+ return;
2282
+ }
2283
+ catch (err) {
2284
+ // log error
2285
+ console.error(err);
2286
+ // call error handler, if defined
2287
+ if (options && options.errorHandler) {
2288
+ options.errorHandler(err);
2289
+ }
2290
+ else {
2291
+ // use default error service
2292
+ this._errorService.showError(err, {
2293
+ continueLink: '.'
2294
+ });
2295
+ }
2296
+ }
2297
+ finally {
2298
+ this._loading.hideLoading();
2299
+ }
2300
+ });
2301
+ }
2302
+ getExportableData() {
2303
+ if (!(this.dataTable && this.dataTable.buttons
2304
+ && typeof this.dataTable.buttons.exportData === 'function' && this.config)) {
2305
+ return { body: [], header: [] };
2306
+ }
2307
+ // fetch exportable excel data
2308
+ let { body, header } = this.dataTable.buttons.exportData();
2309
+ const cleanupIndexes = [];
2310
+ // clean up headers
2311
+ header = header.filter((headerItem, index) => {
2312
+ // exclude empty headers
2313
+ if (headerItem.trim().length === 0) {
2314
+ cleanupIndexes.push(index);
2315
+ return false;
2316
+ }
2317
+ // find item by title
2318
+ const findItem = this.config.columns.find((column) => {
2319
+ return column.title && column.title.length && this._translateService.instant(column.title) === headerItem;
2320
+ });
2321
+ // exclude hidden columns
2322
+ if (findItem && findItem.hidden === true) {
2323
+ cleanupIndexes.push(index);
2324
+ return false;
2325
+ }
2326
+ return true;
2327
+ });
2328
+ // clean up body
2329
+ body = body.map((row) => {
2330
+ return row.filter((_, rowIndex) => {
2331
+ return cleanupIndexes.indexOf(rowIndex) === -1;
2332
+ });
2333
+ });
2334
+ return { body, header };
2335
+ }
1934
2336
  }
1935
2337
  AdvancedTableComponent.decorators = [
1936
2338
  { type: Component, args: [{
@@ -1981,7 +2383,11 @@ AdvancedTableComponent.ctorParameters = () => [
1981
2383
  { type: TemplatePipe },
1982
2384
  { type: LoadingService },
1983
2385
  { type: HttpClient },
1984
- { type: ColumnSelectorService }
2386
+ { type: ColumnSelectorService },
2387
+ { type: ConfigurationService },
2388
+ { type: ExportSpreadsheetService },
2389
+ { type: ModalService },
2390
+ { type: ErrorService }
1985
2391
  ];
1986
2392
  AdvancedTableComponent.propDecorators = {
1987
2393
  table: [{ type: ViewChild, args: ['table',] }],
@@ -3035,37 +3441,6 @@ AdvancedSearchConfigurationResolver.ctorParameters = () => [
3035
3441
  { type: HttpClient }
3036
3442
  ];
3037
3443
 
3038
- class ActivatedTableService {
3039
- constructor(_router, _activatedRoute) {
3040
- this._router = _router;
3041
- this._activatedRoute = _activatedRoute;
3042
- _router.events.forEach((event) => {
3043
- if (event instanceof NavigationStart) {
3044
- if (this._activeTable) {
3045
- this._activeTable = null;
3046
- }
3047
- }
3048
- });
3049
- }
3050
- get activeTable() {
3051
- return this._activeTable;
3052
- }
3053
- set activeTable(tableComponent) {
3054
- this._activeTable = tableComponent;
3055
- }
3056
- }
3057
- ActivatedTableService.decorators = [
3058
- { type: Injectable, args: [{
3059
- providedIn: 'root'
3060
- },] }
3061
- ];
3062
- /** @nocollapse */
3063
- ActivatedTableService.ctorParameters = () => [
3064
- { type: Router },
3065
- { type: ActivatedRoute }
3066
- ];
3067
- ActivatedTableService.ngInjectableDef = defineInjectable({ factory: function ActivatedTableService_Factory() { return new ActivatedTableService(inject(Router), inject(ActivatedRoute)); }, token: ActivatedTableService, providedIn: "root" });
3068
-
3069
3444
  class AdvancedTableSettingsComponent {
3070
3445
  constructor(_context, _activatedRoute, elRef, modalService, userStorage, formBuilder, _activatedTable) {
3071
3446
  this._context = _context;
@@ -3895,226 +4270,6 @@ AdvancedTableEditorDirective.propDecorators = {
3895
4270
  dirtyChange: [{ type: Output }]
3896
4271
  };
3897
4272
 
3898
- const MAX_EXPORT_ITEMS = 500;
3899
- class BtnExpDirective {
3900
- constructor(_activatedTable, _context, _config, _translate, _loadingService, _errorService) {
3901
- this._activatedTable = _activatedTable;
3902
- this._context = _context;
3903
- this._config = _config;
3904
- this._translate = _translate;
3905
- this._loadingService = _loadingService;
3906
- this._errorService = _errorService;
3907
- }
3908
- clickEvent(event) {
3909
- return __awaiter(this, void 0, void 0, function* () {
3910
- event.preventDefault();
3911
- event.stopPropagation();
3912
- if (this._activatedTable.activeTable) {
3913
- const lastQuery = this._activatedTable.activeTable.lastQuery;
3914
- const tableConfig = this._activatedTable.activeTable.config;
3915
- const serviceHeaders = this._context.getService().getHeaders();
3916
- const queryModel = lastQuery.getModel();
3917
- let query = this._context.model(queryModel).asQueryable();
3918
- const queryParams = lastQuery.getParams();
3919
- query = this.constructQuery(query, queryParams, tableConfig, serviceHeaders);
3920
- // get export settings
3921
- const exportSettings = this._config.settings;
3922
- // get export limit
3923
- const maxExportItems = exportSettings && exportSettings.tables && exportSettings.tables.exportLimit;
3924
- if (maxExportItems && typeof maxExportItems === 'number' && maxExportItems > 0) {
3925
- query.skip(0).take(maxExportItems);
3926
- }
3927
- else {
3928
- query.skip(0).take(MAX_EXPORT_ITEMS);
3929
- }
3930
- // This constructs the URI based on the way @themost does
3931
- const url = this.constructURL(query);
3932
- this.downloadFile(url, query.getService().getHeaders(), query.getModel());
3933
- }
3934
- });
3935
- }
3936
- /**
3937
- * Sets the parameters to the query based on
3938
- * the active filters of the activated table
3939
- * @param {ClientDataQueryable} query
3940
- * @param params: The filters of the last query of the activated table
3941
- * @return ClientDataQueryable
3942
- */
3943
- setParams(query, params) {
3944
- if (params && typeof params === 'object') {
3945
- Object.keys(params).forEach((key) => {
3946
- query.setParam(key, params[key]);
3947
- });
3948
- }
3949
- return query;
3950
- }
3951
- /**
3952
- * Sets the headers to the query based on
3953
- * the default headers of the DataContext
3954
- * and appending the accept header to get
3955
- * an xlsx file from the API
3956
- * @param {ClientDataQueryable} query
3957
- * @param {Headers} headers: The headers to append to the query
3958
- * @return ClientDataQueryable
3959
- */
3960
- setHeaders(query, headers) {
3961
- Object.keys(headers).forEach((key) => {
3962
- if (headers.hasOwnProperty(key)) {
3963
- query.getService().setHeader(key, headers[key]);
3964
- }
3965
- });
3966
- // sets a header to accept xlsx files
3967
- query.getService().setHeader('Accept', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
3968
- return query;
3969
- }
3970
- /**
3971
- * Constructs the select parameter of the
3972
- * ClientDataQuery by replacing the target name
3973
- * of the field based on the localized translation
3974
- * of that property on the advanced tabled
3975
- * @param {ClientDataQueryable} query
3976
- * @param tableConfig: The configuration of the activated table
3977
- * @return ClientDataQueryable
3978
- */
3979
- constructQueryParam(query, tableConfig) {
3980
- let selectQuery = query.getParams().$select;
3981
- let selectQueryArray = selectQuery.split(',');
3982
- selectQueryArray = selectQueryArray.map((select$$1) => {
3983
- const words = select$$1.split(' ');
3984
- if (words.length === 3) {
3985
- if (tableConfig && tableConfig.columns) {
3986
- for (const column of tableConfig.columns) {
3987
- if (column.property === words[2] && column.title) {
3988
- words[2] = `"${this._translate.instant(column.title)}"`;
3989
- }
3990
- else if (column.property === words[2]) {
3991
- words[2] = `"${this._translate.instant(words[2])}"`;
3992
- }
3993
- }
3994
- }
3995
- }
3996
- if (words.length === 1) {
3997
- if (tableConfig && tableConfig.columns) {
3998
- for (const column of tableConfig.columns) {
3999
- if (column.name === words[0] && column.title) {
4000
- words[0] = `${words[0]} as "${this._translate.instant(column.title)}"`;
4001
- break;
4002
- }
4003
- else if (column.name === words[0] && column.property) {
4004
- words[0] = `${words[0]} as "${this._translate.instant(column.property)}"`;
4005
- break;
4006
- }
4007
- else if (words[0] === column.name && words[0] === "id" && column.hidden) {
4008
- break;
4009
- }
4010
- else if (words[0] == column.name || words[0] === column.property) {
4011
- words[0] = `${words[0]} as "${this._translate.instant(words[0])}"`;
4012
- }
4013
- }
4014
- }
4015
- return words[0];
4016
- }
4017
- return words.join(' ');
4018
- });
4019
- selectQuery = selectQueryArray.join(',');
4020
- query.setParam('$select', selectQuery);
4021
- return query;
4022
- }
4023
- /**
4024
- * Constructs the fetch URL based the query parameters
4025
- * @param {ClientDataQueryable} query
4026
- * @return String
4027
- */
4028
- constructURL(query) {
4029
- const baseURL = query.getService().getBase();
4030
- let url = baseURL.endsWith('/') ? (baseURL + query.getModel() + '?') : (baseURL + '/' + query.getModel() + '?');
4031
- Object.keys(query.getParams()).forEach((key, index) => {
4032
- if (index === 0) {
4033
- url += key + '=' + query.getParams()[key];
4034
- }
4035
- else {
4036
- url += '&' + key + '=' + query.getParams()[key];
4037
- }
4038
- });
4039
- return url;
4040
- }
4041
- /**
4042
- * Constructs the query by setting the parameters of the
4043
- * advanced table's active filters, sets the necessary headers
4044
- * and build the select parameter of the query
4045
- * @param {ClientDataQueryable} query
4046
- * @param params: The filters of the last query of the activated table
4047
- * @param tableConfig: The configuration of the activated table
4048
- * @param {Headers} headers: The headers to append to the query
4049
- * @return ClientDataQueryable
4050
- */
4051
- constructQuery(query, params, tableConfig, headers) {
4052
- let _query = this.setParams(query, params);
4053
- _query = this.setHeaders(_query, headers);
4054
- _query = this.constructQueryParam(_query, tableConfig);
4055
- return _query;
4056
- }
4057
- /**
4058
- * Fetches and saves the xlsx file
4059
- * @param {String} url
4060
- * @param {Headers} serviceHeaders: The headers to append to the query
4061
- * @param modelName: The model name of the advanced table
4062
- */
4063
- downloadFile(url, serviceHeaders, modelName) {
4064
- this._loadingService.showLoading();
4065
- fetch(encodeURI(url), {
4066
- headers: serviceHeaders,
4067
- credentials: 'include'
4068
- }).then(response => {
4069
- if (response && !response.ok) {
4070
- throw new ResponseError(response.statusText, response.status);
4071
- }
4072
- return response.blob();
4073
- }).then(blob => {
4074
- const objectUrl = window.URL.createObjectURL(blob);
4075
- const a = document.createElement('a');
4076
- document.body.appendChild(a);
4077
- a.setAttribute('style', 'display: none');
4078
- a.href = objectUrl;
4079
- const downloadName = `${modelName}.xlsx`;
4080
- a.download = downloadName;
4081
- // this adds support for IE and MS Edge (up to version 44.19041)
4082
- if (window.navigator && window.navigator.msSaveOrOpenBlob) {
4083
- window.navigator.msSaveOrOpenBlob(blob, downloadName);
4084
- }
4085
- else {
4086
- // for all other browsers
4087
- a.click();
4088
- }
4089
- window.URL.revokeObjectURL(objectUrl);
4090
- a.remove();
4091
- this._loadingService.hideLoading();
4092
- }).catch(err => {
4093
- this._loadingService.hideLoading();
4094
- this._errorService.showError(err, {
4095
- continueLink: '.'
4096
- });
4097
- });
4098
- }
4099
- }
4100
- BtnExpDirective.decorators = [
4101
- { type: Directive, args: [{
4102
- selector: '.universis-btn-export'
4103
- },] }
4104
- ];
4105
- /** @nocollapse */
4106
- BtnExpDirective.ctorParameters = () => [
4107
- { type: ActivatedTableService },
4108
- { type: AngularDataContext },
4109
- { type: ConfigurationService },
4110
- { type: TranslateService },
4111
- { type: LoadingService },
4112
- { type: ErrorService }
4113
- ];
4114
- BtnExpDirective.propDecorators = {
4115
- clickEvent: [{ type: HostListener, args: ['click', ['$event'],] }]
4116
- };
4117
-
4118
4273
  class AdvancedAggregatorService {
4119
4274
  constructor(_context, _template) {
4120
4275
  this._context = _context;
@@ -4600,6 +4755,8 @@ ParseTitlePipe.ctorParameters = () => [
4600
4755
  { type: TranslateService }
4601
4756
  ];
4602
4757
 
4758
+ // tslint:disable: quotemark
4759
+ // tslint:disable: max-line-length
4603
4760
  const TABLES_EL = {
4604
4761
  "Tables": {
4605
4762
  "Export": "Εξαγωγή",
@@ -4683,7 +4840,10 @@ const TABLES_EL = {
4683
4840
  "DataError": {
4684
4841
  "Title": "Σφάλμα κατά την παραλαβή των δεδομένων",
4685
4842
  "Message": "Συνέβη σφάλμα κατά την παραλαβή των δεδομένων. Προσπαθήστε ξανά ή τροποποιήστε τα στοιχεία αναζήτησης."
4686
- }
4843
+ },
4844
+ "ExportList": "Εξαγωγή λίστας",
4845
+ "ExportLimitExceeded": "Το πλήθος των στοιχείων προς εξαγωγή ({{dataLength}}) ξεπερνάει το μέγιστο επιτρεπτό ({{exportLimit}}). Παρακαλούμε προσαρμόστε τα φίλτρα της αναζήτησης και προσπαθήστε ξανά.",
4846
+ "ExportResults": "Δεδομένα λίστας"
4687
4847
  },
4688
4848
  "TrueFalse": {
4689
4849
  "long": {
@@ -4724,6 +4884,8 @@ const TABLES_EL = {
4724
4884
  }
4725
4885
  };
4726
4886
 
4887
+ // tslint:disable: quotemark
4888
+ // tslint:disable: max-line-length
4727
4889
  const TABLES_EN = {
4728
4890
  "Tables": {
4729
4891
  "Export": "Export",
@@ -4806,7 +4968,10 @@ const TABLES_EN = {
4806
4968
  "DataError": {
4807
4969
  "Title": "Error while getting data",
4808
4970
  "Message": "An error occurred while getting data. Please try again or change your criteria."
4809
- }
4971
+ },
4972
+ "ExportList": "Export list",
4973
+ "ExportLimitExceeded": "The number of items that are to be exported ({{dataLength}}) exceeds the export limit ({{exportLimit}}). Please apply more specific filters to the search.",
4974
+ "ExportResults": "Exported list"
4810
4975
  },
4811
4976
  "TrueFalse": {
4812
4977
  "long": {
@@ -5217,6 +5382,6 @@ TablesModule.ctorParameters = () => [
5217
5382
  * Generated bundle index. Do not edit.
5218
5383
  */
5219
5384
 
5220
- export { AdvancedSearchState as ɵa, AdvancedTableState as ɵc, AdvancedSearchRouterState as ɵd, AdvancedListComponent, AdvancedRowActionComponent, AdvancedSearchFormComponent, AdvancedSelectComponent, AdvancedSelectService, AdvancedTableConfigurationResolver, AdvancedSearchConfigurationResolver, AdvancedColumnFormatter, NestedPropertyFormatter, ButtonFormatter, LinkFormatter, ActionLinkFormatter, ActionButtonFormatter, ActionSplitButtonFormatter, SelectRowFormatter, TemplateFormatter, TrueFalseFormatter, TranslationFormatter, DateTimeFormatter, NgClassFormatter, LanguageFormatter, COLUMN_FORMATTERS, AdvancedTableConfiguration, AdvancedTableComponent, ɵ0, AdvancedTableSettingsComponent, AdvancedTableSearchBaseComponent, AdvancedTableSearchComponent, FORMATTERS, AdvancedFilterValueProvider, AdvancedTableModalBaseTemplate, AdvancedTableModalBaseComponent, SimpleHeaderToolsComponent, TableSimpleHeaderComponent, AdvancedTableNotNullError, AdvancedTableEditorDirective, BtnExpDirective, AdvancedAggregatorComponent, AdvancedAggregatorListComponent, AddItemsComponent, AdvancedAggregatorPipe, ParseTitlePipe, AdvancedAggregatorService, TablesModule, ActivatedTableService, ColumnSelectorService, ColumnSelectorComponent, initialState, tableInitialState, tableReducer, tableReducers, featureName, getTablesState, selectTable };
5385
+ export { AdvancedSearchState as ɵa, AdvancedTableState as ɵc, AdvancedSearchRouterState as ɵd, AdvancedListComponent, AdvancedRowActionComponent, AdvancedSearchFormComponent, AdvancedSelectComponent, AdvancedSelectService, AdvancedTableConfigurationResolver, AdvancedSearchConfigurationResolver, AdvancedColumnFormatter, NestedPropertyFormatter, ButtonFormatter, LinkFormatter, ActionLinkFormatter, ActionButtonFormatter, ActionSplitButtonFormatter, SelectRowFormatter, TemplateFormatter, TrueFalseFormatter, TranslationFormatter, DateTimeFormatter, NgClassFormatter, LanguageFormatter, COLUMN_FORMATTERS, ExportLimitExceededError, AdvancedTableConfiguration, AdvancedTableComponent, ɵ0, AdvancedTableSettingsComponent, AdvancedTableSearchBaseComponent, AdvancedTableSearchComponent, FORMATTERS, AdvancedFilterValueProvider, AdvancedTableModalBaseTemplate, AdvancedTableModalBaseComponent, SimpleHeaderToolsComponent, TableSimpleHeaderComponent, AdvancedTableNotNullError, AdvancedTableEditorDirective, MAX_EXPORT_ITEMS, BtnExpDirective, AdvancedAggregatorComponent, AdvancedAggregatorListComponent, AddItemsComponent, AdvancedAggregatorPipe, ParseTitlePipe, AdvancedAggregatorService, TablesModule, ActivatedTableService, ColumnSelectorService, ColumnSelectorComponent, initialState, tableInitialState, tableReducer, tableReducers, featureName, getTablesState, selectTable };
5221
5386
 
5222
5387
  //# sourceMappingURL=universis-ngx-tables.js.map