]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/eg2/src/app/share/grid/grid.component.ts
LP#1850547: eg-grid: Add ignoreFields support to suppress selected IDL-generated...
[Evergreen.git] / Open-ILS / src / eg2 / src / app / share / grid / grid.component.ts
1 import {Component, Input, Output, OnInit, AfterViewInit, EventEmitter,
2     OnDestroy, ViewChild, ViewEncapsulation} from '@angular/core';
3 import {IdlService} from '@eg/core/idl.service';
4 import {OrgService} from '@eg/core/org.service';
5 import {ServerStoreService} from '@eg/core/server-store.service';
6 import {FormatService} from '@eg/core/format.service';
7 import {GridContext, GridColumn, GridDataSource,
8     GridCellTextGenerator, GridRowFlairEntry} from './grid';
9 import {GridToolbarComponent} from './grid-toolbar.component';
10
11 /**
12  * Main grid entry point.
13  */
14
15 @Component({
16   selector: 'eg-grid',
17   templateUrl: './grid.component.html',
18   styleUrls: ['grid.component.css'],
19   // share grid css globally once imported so all grid component CSS
20   // can live in grid.component.css and to avoid multiple copies of
21   // the CSS when multiple grids are displayed.
22   encapsulation: ViewEncapsulation.None
23 })
24
25 export class GridComponent implements OnInit, AfterViewInit, OnDestroy {
26
27     // Source of row data.
28     @Input() dataSource: GridDataSource;
29
30     // IDL class for auto-generation of columns
31     @Input() idlClass: string;
32
33     // True if any columns are sortable
34     @Input() sortable: boolean;
35
36     // True if the grid supports sorting of multiple columns at once
37     @Input() multiSortable: boolean;
38
39     // If true, grid sort requests only operate on data that
40     // already exists in the grid data source -- no row fetching.
41     // The assumption is all data is already available.
42     @Input() useLocalSort: boolean;
43
44     // Storage persist key / per-grid-type unique identifier
45     // The value is prefixed with 'eg.grid.'
46     //
47     // If persistKey is set to "disabled", or does not exist,
48     // the grid will not display a Save button to the user
49     @Input() persistKey: string;
50
51     @Input() disableSelect: boolean;
52
53     // Prevent selection of multiple rows
54     @Input() disableMultiSelect: boolean;
55
56     // Show an extra column in the grid where the caller can apply
57     // row-specific flair (material icons).
58     @Input() rowFlairIsEnabled: boolean;
59
60     // Returns a material icon name to display in the flar column
61     // (if enabled) for the given row.
62     @Input() rowFlairCallback: (row: any) => GridRowFlairEntry;
63
64     // Returns a space-separated list of CSS class names to apply to
65     // a given row
66     @Input() rowClassCallback: (row: any) => string;
67
68     // Returns a space-separated list of CSS class names to apply to
69     // a given cell or all cells in a column.
70     @Input() cellClassCallback: (row: any, col: GridColumn) => string;
71
72     // comma-separated list of fields to show by default.
73     // This field takes precedence over hideFields.
74     // When a value is applied, any field not in this list will
75     // be hidden.
76     @Input() showFields: string;
77
78     // comma-separated list of fields to hide.
79     // This does not imply all other fields should be visible, only that
80     // the selected fields will be hidden.
81     @Input() hideFields: string;
82
83     // comma-separated list of fields to ignore when generating columns
84     // from the IDL.
85     // This does not imply all other fields should be available, only
86     // that the selected fields will be ignored.
87     @Input() ignoreFields: string;
88
89     // When true, only display columns that are declared in the markup
90     // and leave all auto-generated fields hidden.
91     @Input() showDeclaredFieldsOnly: boolean;
92
93     // Allow the caller to jump directly to a specific page of
94     // grid data.
95     @Input() pageOffset: number;
96     // Pass in a default page size.  May be overridden by settings.
97     @Input() pageSize: number;
98
99     @Input() showLinkSelectors: boolean;
100
101     @Input() disablePaging: boolean;
102
103     // result filtering
104     //
105     // filterable: true if the result filtering controls
106     // should be displayed
107     @Input() filterable: boolean;
108
109     // sticky grid header
110     //
111     // stickyHeader: true of the grid header should be
112     // "sticky", i.e., remain visible if if the table is long
113     // and the user has scrolled far enough that the header
114     // would go out of view
115     @Input() stickyHeader: boolean;
116
117     @Input() cellTextGenerator: GridCellTextGenerator;
118
119     context: GridContext;
120
121     // These events are emitted from our grid-body component.
122     // They are defined here for ease of access to the caller.
123     @Output() onRowActivate: EventEmitter<any>;
124     @Output() onRowClick: EventEmitter<any>;
125
126     @ViewChild('toolbar', { static: true }) toolbar: GridToolbarComponent;
127
128     constructor(
129         private idl: IdlService,
130         private org: OrgService,
131         private store: ServerStoreService,
132         private format: FormatService
133     ) {
134         this.context =
135             new GridContext(this.idl, this.org, this.store, this.format);
136         this.onRowActivate = new EventEmitter<any>();
137         this.onRowClick = new EventEmitter<any>();
138     }
139
140     ngOnInit() {
141
142         if (!this.dataSource) {
143             throw new Error('<eg-grid/> requires a [dataSource]');
144         }
145
146         this.context.idlClass = this.idlClass;
147         this.context.dataSource = this.dataSource;
148         this.context.persistKey = this.persistKey;
149         this.context.isSortable = this.sortable === true;
150         this.context.isFilterable = this.filterable === true;
151         this.context.stickyGridHeader = this.stickyHeader === true;
152         this.context.isMultiSortable = this.multiSortable === true;
153         this.context.useLocalSort = this.useLocalSort === true;
154         this.context.disableSelect = this.disableSelect === true;
155         this.context.disableMultiSelect = this.disableMultiSelect === true;
156         this.context.rowFlairIsEnabled = this.rowFlairIsEnabled  === true;
157         this.context.showDeclaredFieldsOnly = this.showDeclaredFieldsOnly;
158         this.context.rowFlairCallback = this.rowFlairCallback;
159         this.context.disablePaging = this.disablePaging === true;
160         this.context.cellTextGenerator = this.cellTextGenerator;
161         this.context.ignoredFields = [];
162
163         if (this.showFields) {
164             this.context.defaultVisibleFields = this.showFields.split(',');
165         }
166         if (this.hideFields) {
167             this.context.defaultHiddenFields = this.hideFields.split(',');
168         }
169         if (this.ignoreFields) {
170             this.context.ignoredFields = this.ignoreFields.split(',');
171         }
172
173         if (this.pageOffset) {
174             this.context.pager.offset = this.pageOffset;
175         }
176
177         if (this.pageSize) {
178             this.context.pager.limit = this.pageSize;
179         }
180
181         // TS doesn't seem to like: let foo = bar || () => '';
182         this.context.rowClassCallback =
183             this.rowClassCallback || function () { return ''; };
184         this.context.cellClassCallback =
185             this.cellClassCallback || function() { return ''; };
186
187         if (this.showLinkSelectors) {
188             console.debug(
189                 'showLinkSelectors is deprecated and no longer has any effect');
190         }
191
192         this.context.init();
193     }
194
195     ngAfterViewInit() {
196         this.context.initData();
197     }
198
199     ngOnDestroy() {
200         this.context.destroy();
201     }
202
203     print = () => {
204         this.toolbar.printHtml();
205     }
206
207     reload() {
208         this.context.reload();
209     }
210     reloadWithoutPagerReset() {
211         this.context.reloadWithoutPagerReset();
212     }
213
214
215 }
216
217
218