namirasoft-site-react 1.5.9 → 1.5.11
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.
- package/dist/components/NSListMenu.d.ts +2 -0
- package/dist/components/NSListMenu.js +26 -9
- package/dist/components/NSListMenu.js.map +1 -1
- package/dist/components/NSReorderDialog.d.ts +30 -0
- package/dist/components/NSReorderDialog.js +73 -0
- package/dist/components/NSReorderDialog.js.map +1 -0
- package/dist/components/NSReorderDialog.module.css +50 -0
- package/dist/components/NSSortDialog.d.ts +21 -0
- package/dist/components/NSSortDialog.js +67 -0
- package/dist/components/NSSortDialog.js.map +1 -0
- package/dist/components/NSTable.d.ts +17 -1
- package/dist/components/NSTable.js +117 -39
- package/dist/components/NSTable.js.map +1 -1
- package/dist/components/NSTable.module.css +1 -0
- package/dist/formatter/BaseColumnFormatter.d.ts +7 -0
- package/dist/formatter/BaseColumnFormatter.js +53 -0
- package/dist/formatter/BaseColumnFormatter.js.map +1 -1
- package/dist/formatter/BaseURLImageFormatter.d.ts +1 -0
- package/dist/formatter/BaseURLImageFormatter.js +3 -0
- package/dist/formatter/BaseURLImageFormatter.js.map +1 -1
- package/dist/formatter/BooleanFormatter.d.ts +1 -0
- package/dist/formatter/BooleanFormatter.js +3 -0
- package/dist/formatter/BooleanFormatter.js.map +1 -1
- package/dist/formatter/BytesFormatter.d.ts +1 -0
- package/dist/formatter/BytesFormatter.js +3 -0
- package/dist/formatter/BytesFormatter.js.map +1 -1
- package/dist/formatter/DateFormatter.d.ts +1 -0
- package/dist/formatter/DateFormatter.js +3 -0
- package/dist/formatter/DateFormatter.js.map +1 -1
- package/dist/formatter/DateTimeFormatter.d.ts +1 -0
- package/dist/formatter/DateTimeFormatter.js +3 -0
- package/dist/formatter/DateTimeFormatter.js.map +1 -1
- package/dist/formatter/DurationFormatter.d.ts +1 -0
- package/dist/formatter/DurationFormatter.js +3 -0
- package/dist/formatter/DurationFormatter.js.map +1 -1
- package/dist/formatter/EmailFormatter.d.ts +1 -0
- package/dist/formatter/EmailFormatter.js +3 -0
- package/dist/formatter/EmailFormatter.js.map +1 -1
- package/dist/formatter/EnumFormatter.d.ts +1 -0
- package/dist/formatter/EnumFormatter.js +3 -0
- package/dist/formatter/EnumFormatter.js.map +1 -1
- package/dist/formatter/FloatFormatter.d.ts +1 -0
- package/dist/formatter/FloatFormatter.js +3 -0
- package/dist/formatter/FloatFormatter.js.map +1 -1
- package/dist/formatter/IDFormatter.d.ts +1 -0
- package/dist/formatter/IDFormatter.js +3 -0
- package/dist/formatter/IDFormatter.js.map +1 -1
- package/dist/formatter/IPFormatter.d.ts +1 -0
- package/dist/formatter/IPFormatter.js +23 -0
- package/dist/formatter/IPFormatter.js.map +1 -1
- package/dist/formatter/IntegerFormatter.d.ts +1 -0
- package/dist/formatter/IntegerFormatter.js +3 -0
- package/dist/formatter/IntegerFormatter.js.map +1 -1
- package/dist/formatter/JsonFormatter.d.ts +1 -0
- package/dist/formatter/JsonFormatter.js +13 -0
- package/dist/formatter/JsonFormatter.js.map +1 -1
- package/dist/formatter/MoneyFormatter.d.ts +1 -0
- package/dist/formatter/MoneyFormatter.js +3 -0
- package/dist/formatter/MoneyFormatter.js.map +1 -1
- package/dist/formatter/PercentFormatter.d.ts +1 -0
- package/dist/formatter/PercentFormatter.js +3 -0
- package/dist/formatter/PercentFormatter.js.map +1 -1
- package/dist/formatter/PhoneFormatter.d.ts +1 -0
- package/dist/formatter/PhoneFormatter.js +3 -0
- package/dist/formatter/PhoneFormatter.js.map +1 -1
- package/dist/formatter/SensitiveFormatter.d.ts +1 -0
- package/dist/formatter/SensitiveFormatter.js +3 -0
- package/dist/formatter/SensitiveFormatter.js.map +1 -1
- package/dist/formatter/StringFormatter.d.ts +1 -0
- package/dist/formatter/StringFormatter.js +3 -0
- package/dist/formatter/StringFormatter.js.map +1 -1
- package/dist/formatter/TimeFormatter.d.ts +1 -0
- package/dist/formatter/TimeFormatter.js +3 -0
- package/dist/formatter/TimeFormatter.js.map +1 -1
- package/dist/formatter/URLFormatter.d.ts +1 -0
- package/dist/formatter/URLFormatter.js +3 -0
- package/dist/formatter/URLFormatter.js.map +1 -1
- package/dist/formatter/UnknowFormatter.d.ts +1 -0
- package/dist/formatter/UnknowFormatter.js +3 -0
- package/dist/formatter/UnknowFormatter.js.map +1 -1
- package/dist/main.d.ts +2 -1
- package/dist/main.js +2 -1
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
- package/src/components/NSListMenu.tsx +43 -12
- package/src/components/NSReorderDialog.module.css +50 -0
- package/src/components/NSReorderDialog.tsx +155 -0
- package/src/components/NSSortDialog.tsx +125 -0
- package/src/components/NSTable.module.css +1 -0
- package/src/components/NSTable.tsx +207 -68
- package/src/formatter/BaseColumnFormatter.ts +68 -0
- package/src/formatter/BaseURLImageFormatter.tsx +4 -0
- package/src/formatter/BooleanFormatter.ts +4 -0
- package/src/formatter/BytesFormatter.tsx +4 -0
- package/src/formatter/DateFormatter.ts +4 -0
- package/src/formatter/DateTimeFormatter.ts +4 -0
- package/src/formatter/DurationFormatter.ts +4 -0
- package/src/formatter/EmailFormatter.tsx +4 -0
- package/src/formatter/EnumFormatter.ts +4 -0
- package/src/formatter/FloatFormatter.ts +4 -0
- package/src/formatter/IDFormatter.tsx +5 -1
- package/src/formatter/IPFormatter.ts +26 -0
- package/src/formatter/IntegerFormatter.ts +4 -0
- package/src/formatter/JsonFormatter.tsx +17 -0
- package/src/formatter/MoneyFormatter.ts +4 -0
- package/src/formatter/PercentFormatter.tsx +4 -0
- package/src/formatter/PhoneFormatter.tsx +4 -0
- package/src/formatter/SensitiveFormatter.tsx +4 -0
- package/src/formatter/StringFormatter.tsx +4 -0
- package/src/formatter/TimeFormatter.ts +4 -0
- package/src/formatter/URLFormatter.tsx +4 -0
- package/src/formatter/UnknowFormatter.ts +4 -0
- package/src/main.ts +2 -1
- package/dist/routing/NSRoutes.d.ts +0 -11
- package/dist/routing/NSRoutes.js +0 -14
- package/dist/routing/NSRoutes.js.map +0 -1
- package/src/routing/NSRoutes.tsx +0 -31
|
@@ -10,6 +10,8 @@ import { NSDialogPageSelection } from './NSDialogPageSelection';
|
|
|
10
10
|
import { NSLoading } from './NSLoading';
|
|
11
11
|
import { NSNoData } from './NSNoData';
|
|
12
12
|
import { NSPagination } from './NSPagination';
|
|
13
|
+
import { NSReorderDialog } from './NSReorderDialog';
|
|
14
|
+
import { NSSortDialog } from './NSSortDialog';
|
|
13
15
|
import { NSTableChart } from './NSTableChart';
|
|
14
16
|
import Styles from './NSTable.module.css';
|
|
15
17
|
|
|
@@ -69,12 +71,22 @@ export interface NSTableProps<RowType> extends IBaseComponentProps
|
|
|
69
71
|
onSelectedIDsChanged?: () => void;
|
|
70
72
|
onSortChanged?: (items: SortItem[] | null) => void;
|
|
71
73
|
onVisibleColumnsChanged?: (visible_columns: { table: string, column: string }[]) => void;
|
|
74
|
+
sort?: NSTableSortConfig;
|
|
72
75
|
ui?: {
|
|
73
76
|
pagination?: boolean;
|
|
74
|
-
button_panel?: boolean;
|
|
77
|
+
button_panel?: boolean | NSTableButtonPanelConfig;
|
|
75
78
|
};
|
|
76
79
|
}
|
|
77
80
|
|
|
81
|
+
export interface NSTableSortConfig
|
|
82
|
+
{
|
|
83
|
+
enabled?: boolean;
|
|
84
|
+
onSort?: (items: SortItem[] | null) => void;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type NSTableButtonKey = "reorder" | "sort" | "fullscreen" | "chart" | "export" | "print" | "refresh";
|
|
88
|
+
export type NSTableButtonPanelConfig = { [key in NSTableButtonKey]?: boolean };
|
|
89
|
+
|
|
78
90
|
interface NSTableState<RowType>
|
|
79
91
|
{
|
|
80
92
|
columns: TableColumnInfo[];
|
|
@@ -94,6 +106,8 @@ interface NSTableState<RowType>
|
|
|
94
106
|
columnWidths: { [key: string]: number };
|
|
95
107
|
fullscreen: boolean;
|
|
96
108
|
showChart: boolean;
|
|
109
|
+
showSortDialog: boolean;
|
|
110
|
+
showReorderDialog: boolean;
|
|
97
111
|
}
|
|
98
112
|
|
|
99
113
|
enum PageSelectionMode
|
|
@@ -129,6 +143,8 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
129
143
|
columnWidths: this.loadColumnWidths(),
|
|
130
144
|
fullscreen: false,
|
|
131
145
|
showChart: false,
|
|
146
|
+
showSortDialog: false,
|
|
147
|
+
showReorderDialog: false,
|
|
132
148
|
};
|
|
133
149
|
this.getSortItemsKey = this.getSortItemsKey.bind(this);
|
|
134
150
|
this.getSortItems = this.getSortItems.bind(this);
|
|
@@ -172,15 +188,58 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
172
188
|
}
|
|
173
189
|
return [];
|
|
174
190
|
}
|
|
191
|
+
isSortEnabled(): boolean
|
|
192
|
+
{
|
|
193
|
+
return this.props.sort?.enabled ?? true;
|
|
194
|
+
}
|
|
195
|
+
private hasCustomSort(): boolean
|
|
196
|
+
{
|
|
197
|
+
return !!this.props.sort?.onSort;
|
|
198
|
+
}
|
|
175
199
|
setSortItems(items: SortItem[] | null)
|
|
176
200
|
{
|
|
201
|
+
if (!this.isSortEnabled())
|
|
202
|
+
return;
|
|
177
203
|
let storage = new IStorageLocal();
|
|
178
204
|
storage.set(this.getSortItemsKey(), SortItem.stringify(items));
|
|
179
205
|
this.setState({ sortItems: items }, () =>
|
|
180
206
|
{
|
|
181
207
|
this.props.onSortChanged?.(items);
|
|
182
|
-
this.
|
|
208
|
+
this.props.sort?.onSort?.(items);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
private compareRowsBySortItems(a: RowType, b: RowType, items: SortItem[]): number
|
|
212
|
+
{
|
|
213
|
+
for (let item of items)
|
|
214
|
+
{
|
|
215
|
+
let column = this.state.columns.find(c => c.table.name === item.table.name && c.name === item.column.name);
|
|
216
|
+
let va = (a as any)[item.column.name];
|
|
217
|
+
let vb = (b as any)[item.column.name];
|
|
218
|
+
let cmp = column ? column.formatter.compare(va, vb) : BaseColumnFormatter.smartCompare(va, vb);
|
|
219
|
+
if (cmp !== 0)
|
|
220
|
+
return item.ascending ? cmp : -cmp;
|
|
221
|
+
}
|
|
222
|
+
return 0;
|
|
223
|
+
}
|
|
224
|
+
private sortRowsClient(rows: RowType[]): RowType[]
|
|
225
|
+
{
|
|
226
|
+
let items = this.state.sortItems;
|
|
227
|
+
if (!items || items.length === 0)
|
|
228
|
+
return rows;
|
|
229
|
+
let decorated = rows.map((row, index) => ({ row, index }));
|
|
230
|
+
decorated.sort((x, y) =>
|
|
231
|
+
{
|
|
232
|
+
let cmp = this.compareRowsBySortItems(x.row, y.row, items!);
|
|
233
|
+
return cmp !== 0 ? cmp : x.index - y.index;
|
|
183
234
|
});
|
|
235
|
+
return decorated.map(d => d.row);
|
|
236
|
+
}
|
|
237
|
+
private getDisplayRows(): RowType[] | null
|
|
238
|
+
{
|
|
239
|
+
let rows = this.state.rows;
|
|
240
|
+
if (!rows || !this.isSortEnabled() || this.hasCustomSort())
|
|
241
|
+
return rows;
|
|
242
|
+
return this.sortRowsClient(rows);
|
|
184
243
|
}
|
|
185
244
|
private getVisibleColumnsKey(): string
|
|
186
245
|
{
|
|
@@ -383,13 +442,14 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
383
442
|
}
|
|
384
443
|
getRowsInRange(fromIndex: number, toIndex: number)
|
|
385
444
|
{
|
|
386
|
-
|
|
445
|
+
let rows = this.getDisplayRows();
|
|
446
|
+
if (!rows)
|
|
387
447
|
return [];
|
|
388
448
|
|
|
389
449
|
let start = Math.min(fromIndex, toIndex);
|
|
390
450
|
let end = Math.max(fromIndex, toIndex);
|
|
391
451
|
|
|
392
|
-
return
|
|
452
|
+
return rows.slice(start, end + 1);
|
|
393
453
|
}
|
|
394
454
|
getSelectedIDs(): string[]
|
|
395
455
|
{
|
|
@@ -420,13 +480,13 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
420
480
|
return v === null || v === undefined ? "" : String(v);
|
|
421
481
|
}).join("");
|
|
422
482
|
}
|
|
423
|
-
private buildChildrenMap(): Map<string, RowType[]> | null
|
|
483
|
+
private buildChildrenMap(rows: RowType[] | null): Map<string, RowType[]> | null
|
|
424
484
|
{
|
|
425
485
|
let h = this.props.hierarchy;
|
|
426
|
-
if (!h || !
|
|
486
|
+
if (!h || !rows)
|
|
427
487
|
return null;
|
|
428
488
|
let map = new Map<string, RowType[]>();
|
|
429
|
-
for (let r of
|
|
489
|
+
for (let r of rows)
|
|
430
490
|
{
|
|
431
491
|
let pid = (r as any)[h.parent];
|
|
432
492
|
let pidKey = pid === null || pid === undefined ? "" : String(pid);
|
|
@@ -590,7 +650,14 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
590
650
|
{
|
|
591
651
|
|
|
592
652
|
let show_pagination = this.props.ui?.pagination ?? true;
|
|
593
|
-
let
|
|
653
|
+
let button_panel_config = this.props.ui?.button_panel;
|
|
654
|
+
let show_button_panel = button_panel_config !== false;
|
|
655
|
+
let isButtonEnabled = (key: NSTableButtonKey): boolean =>
|
|
656
|
+
{
|
|
657
|
+
if (button_panel_config === undefined || typeof button_panel_config === "boolean")
|
|
658
|
+
return true;
|
|
659
|
+
return button_panel_config[key] ?? true;
|
|
660
|
+
};
|
|
594
661
|
let getRowAttributes = (row_value: RowType, row_index: number) =>
|
|
595
662
|
{
|
|
596
663
|
if (this.props.getRowAttributes)
|
|
@@ -656,10 +723,11 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
656
723
|
}
|
|
657
724
|
else
|
|
658
725
|
{
|
|
726
|
+
let displayRows = this.getDisplayRows() ?? [];
|
|
659
727
|
let hierarchical = !!this.props.hierarchy;
|
|
660
|
-
let childrenMap = this.buildChildrenMap();
|
|
728
|
+
let childrenMap = this.buildChildrenMap(displayRows);
|
|
661
729
|
let indexOfRow = new Map<RowType, number>();
|
|
662
|
-
|
|
730
|
+
displayRows.forEach((r, i) => indexOfRow.set(r, i));
|
|
663
731
|
let INDENT = 16;
|
|
664
732
|
let lineColor = "rgba(20, 27, 92, 0.35)";
|
|
665
733
|
let renderRow = (rowValue: RowType, rowIndex: number, depth: number, parentKey: string, ancestorHasNext: boolean[], isLastChild: boolean): React.ReactNode[] =>
|
|
@@ -852,8 +920,8 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
852
920
|
{
|
|
853
921
|
let parentCol = this.props.hierarchy.parent;
|
|
854
922
|
let ids = new Set<string>();
|
|
855
|
-
|
|
856
|
-
topLevel =
|
|
923
|
+
displayRows.forEach(r => ids.add(this.getRowIdValue(r) + "" + this.getGroupKey(r)));
|
|
924
|
+
topLevel = displayRows.filter(r =>
|
|
857
925
|
{
|
|
858
926
|
let pid = (r as any)[parentCol];
|
|
859
927
|
let pidKey = pid === null || pid === undefined ? "" : String(pid);
|
|
@@ -864,7 +932,7 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
864
932
|
}
|
|
865
933
|
else
|
|
866
934
|
{
|
|
867
|
-
topLevel =
|
|
935
|
+
topLevel = displayRows;
|
|
868
936
|
}
|
|
869
937
|
content = topLevel.flatMap((rowValue, i) => renderRow(rowValue, indexOfRow.get(rowValue) ?? 0, 0, "", [], i === topLevel.length - 1));
|
|
870
938
|
}
|
|
@@ -924,6 +992,30 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
924
992
|
onClose={() => this.setState({ pageSelectionMode: PageSelectionMode.Hidden })}
|
|
925
993
|
/>
|
|
926
994
|
}
|
|
995
|
+
{
|
|
996
|
+
isButtonEnabled("reorder") &&
|
|
997
|
+
<NSButton
|
|
998
|
+
attributes={{ title: 'Reorder' }}
|
|
999
|
+
icon={{ src: "https://static.namirasoft.com/image/concept/grip-vertical/blue.svg", alt: "reorder" }}
|
|
1000
|
+
onClick={{
|
|
1001
|
+
action: () => this.setState({ showReorderDialog: true }),
|
|
1002
|
+
showLoading: false
|
|
1003
|
+
}}
|
|
1004
|
+
classList={[Styles.ns_table_button]}
|
|
1005
|
+
/>
|
|
1006
|
+
}
|
|
1007
|
+
{
|
|
1008
|
+
isButtonEnabled("sort") && this.isSortEnabled() &&
|
|
1009
|
+
<NSButton
|
|
1010
|
+
attributes={{ title: 'Sort' }}
|
|
1011
|
+
icon={{ src: "https://static.namirasoft.com/image/concept/arrow-down-short-wide/blue.svg", alt: "sort" }}
|
|
1012
|
+
onClick={{
|
|
1013
|
+
action: () => this.setState({ showSortDialog: true }),
|
|
1014
|
+
showLoading: false
|
|
1015
|
+
}}
|
|
1016
|
+
classList={[Styles.ns_table_button]}
|
|
1017
|
+
/>
|
|
1018
|
+
}
|
|
927
1019
|
{
|
|
928
1020
|
this.props.buttons?.map((button, index) => (
|
|
929
1021
|
<NSButton
|
|
@@ -933,60 +1025,75 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
933
1025
|
/>
|
|
934
1026
|
))
|
|
935
1027
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
{
|
|
984
|
-
this.
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1028
|
+
{
|
|
1029
|
+
isButtonEnabled("fullscreen") &&
|
|
1030
|
+
<NSButton
|
|
1031
|
+
icon={{ src: `https://static.namirasoft.com/image/concept/full-screen/blue.svg` }}
|
|
1032
|
+
classList={[Styles.ns_table_button, Styles.ns_fullscreen_button]}
|
|
1033
|
+
onClick={{
|
|
1034
|
+
action: this.toggleFullscreen,
|
|
1035
|
+
showLoading: false
|
|
1036
|
+
}}
|
|
1037
|
+
attributes={{ title: this.state.fullscreen ? 'Minimize' : 'Maximize' }}
|
|
1038
|
+
/>
|
|
1039
|
+
}
|
|
1040
|
+
{
|
|
1041
|
+
isButtonEnabled("chart") &&
|
|
1042
|
+
<NSButton
|
|
1043
|
+
attributes={{ title: 'Chart' }}
|
|
1044
|
+
icon={{ src: "https://static.namirasoft.com/image/concept/chart/blue.svg" }}
|
|
1045
|
+
onClick={{
|
|
1046
|
+
action: () =>
|
|
1047
|
+
{
|
|
1048
|
+
if (!this.state.rows || this.state.rows.length === 0)
|
|
1049
|
+
this.showModal(" ", "There is no data to display as a chart.");
|
|
1050
|
+
else
|
|
1051
|
+
this.setState({ showChart: true });
|
|
1052
|
+
},
|
|
1053
|
+
showLoading: false
|
|
1054
|
+
}}
|
|
1055
|
+
classList={[Styles.ns_table_button]}
|
|
1056
|
+
/>
|
|
1057
|
+
}
|
|
1058
|
+
{
|
|
1059
|
+
isButtonEnabled("export") &&
|
|
1060
|
+
<NSButton
|
|
1061
|
+
icon={{ src: "https://static.namirasoft.com/image/concept/export/blue.svg" }}
|
|
1062
|
+
onClick={{
|
|
1063
|
+
action: () => { this.setState({ pageSelectionMode: PageSelectionMode.CSV }); },
|
|
1064
|
+
showLoading: false
|
|
1065
|
+
}}
|
|
1066
|
+
classList={[Styles.ns_table_button]}
|
|
1067
|
+
attributes={{ title: 'Export' }}
|
|
1068
|
+
/>
|
|
1069
|
+
}
|
|
1070
|
+
{
|
|
1071
|
+
isButtonEnabled("print") &&
|
|
1072
|
+
<NSButton
|
|
1073
|
+
attributes={{ title: 'Print' }}
|
|
1074
|
+
icon={{ src: "https://static.namirasoft.com/image/concept/print/blue.svg" }}
|
|
1075
|
+
onClick={{
|
|
1076
|
+
action: () => { this.setState({ pageSelectionMode: PageSelectionMode.Print }); },
|
|
1077
|
+
showLoading: false
|
|
1078
|
+
}}
|
|
1079
|
+
classList={[Styles.ns_table_button]}
|
|
1080
|
+
/>
|
|
1081
|
+
}
|
|
1082
|
+
{
|
|
1083
|
+
isButtonEnabled("refresh") &&
|
|
1084
|
+
<NSButton
|
|
1085
|
+
attributes={{ title: 'Refresh' }}
|
|
1086
|
+
icon={{ src: "https://static.namirasoft.com/image/concept/refresh/blue.svg" }}
|
|
1087
|
+
onClick={{
|
|
1088
|
+
action: async (onFinished) =>
|
|
1089
|
+
{
|
|
1090
|
+
this.reload(null, null).then(onFinished).catch(onFinished);
|
|
1091
|
+
}
|
|
1092
|
+
}}
|
|
1093
|
+
classList={[Styles.ns_table_button]}
|
|
1094
|
+
style={{ border: '1px solid rgb(3, 119, 255)' }}
|
|
1095
|
+
/>
|
|
1096
|
+
}
|
|
990
1097
|
</div>
|
|
991
1098
|
);
|
|
992
1099
|
|
|
@@ -1005,7 +1112,7 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
1005
1112
|
}
|
|
1006
1113
|
{
|
|
1007
1114
|
show_pagination &&
|
|
1008
|
-
<NSPagination ref={this.NSPagination} totalItems={this.state.totalItems} onPageChange={this.onPageChange}
|
|
1115
|
+
<NSPagination ref={this.NSPagination} totalItems={this.state.totalItems} onPageChange={this.onPageChange} />
|
|
1009
1116
|
}
|
|
1010
1117
|
{buttonPanel}
|
|
1011
1118
|
</div>
|
|
@@ -1048,6 +1155,8 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
1048
1155
|
{
|
|
1049
1156
|
if ((e.target as HTMLElement).closest('[data-resize-handle]'))
|
|
1050
1157
|
return;
|
|
1158
|
+
if (!this.isSortEnabled())
|
|
1159
|
+
return;
|
|
1051
1160
|
let t = new BaseMetaTable(null, column.table.name, column.table.text);
|
|
1052
1161
|
let c = new BaseMetaColumn(t, column.name, column.text, "", false);
|
|
1053
1162
|
let items = this.getSortItems();
|
|
@@ -1104,6 +1213,36 @@ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableSt
|
|
|
1104
1213
|
onClose={() => this.setState({ showChart: false })}
|
|
1105
1214
|
/>
|
|
1106
1215
|
}
|
|
1216
|
+
{
|
|
1217
|
+
this.state.showSortDialog && this.isSortEnabled() &&
|
|
1218
|
+
<NSSortDialog
|
|
1219
|
+
sorts={this.getSortItems()}
|
|
1220
|
+
getColumns={() => this.getColumns(null)}
|
|
1221
|
+
onCancel={() => this.setState({ showSortDialog: false })}
|
|
1222
|
+
onApply={sorts =>
|
|
1223
|
+
{
|
|
1224
|
+
this.setSortItems(sorts);
|
|
1225
|
+
this.setState({ showSortDialog: false });
|
|
1226
|
+
}}
|
|
1227
|
+
/>
|
|
1228
|
+
}
|
|
1229
|
+
{
|
|
1230
|
+
this.state.showReorderDialog &&
|
|
1231
|
+
<NSReorderDialog
|
|
1232
|
+
visibleColumnKeys={this.getVisibleColumns().map(c => c.table + "." + c.column)}
|
|
1233
|
+
getColumns={() => this.getColumns(null)}
|
|
1234
|
+
onCancel={() => this.setState({ showReorderDialog: false })}
|
|
1235
|
+
onApply={orderedKeys =>
|
|
1236
|
+
{
|
|
1237
|
+
const all = this.getColumns(null);
|
|
1238
|
+
const cs = orderedKeys
|
|
1239
|
+
.map(k => all.find(c => c.table.name + "." + c.name === k))
|
|
1240
|
+
.filter((c): c is TableColumnInfo => !!c);
|
|
1241
|
+
this.setVisibleColumns(cs.map(c => ({ table: c.table.name, column: c.name })));
|
|
1242
|
+
this.setState({ showReorderDialog: false });
|
|
1243
|
+
}}
|
|
1244
|
+
/>
|
|
1245
|
+
}
|
|
1107
1246
|
</div>
|
|
1108
1247
|
);
|
|
1109
1248
|
}
|
|
@@ -6,6 +6,74 @@ export abstract class BaseColumnFormatter
|
|
|
6
6
|
public width: string = "100px";
|
|
7
7
|
public onclick_overrided: boolean = false;
|
|
8
8
|
abstract format(value: any, column: TableColumnInfo, row: TableRowInfo<any>, printable: boolean): any;
|
|
9
|
+
|
|
10
|
+
compare(a: any, b: any): number
|
|
11
|
+
{
|
|
12
|
+
return BaseColumnFormatter.smartCompare(a, b);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static isEmpty(v: any): boolean
|
|
16
|
+
{
|
|
17
|
+
return v === null || v === undefined || v === "";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static compareEmpty(a: any, b: any): number | null
|
|
21
|
+
{
|
|
22
|
+
const ae = BaseColumnFormatter.isEmpty(a);
|
|
23
|
+
const be = BaseColumnFormatter.isEmpty(b);
|
|
24
|
+
if (ae && be)
|
|
25
|
+
return 0;
|
|
26
|
+
if (ae)
|
|
27
|
+
return 1;
|
|
28
|
+
if (be)
|
|
29
|
+
return -1;
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static numberCompare(a: any, b: any): number
|
|
34
|
+
{
|
|
35
|
+
const e = BaseColumnFormatter.compareEmpty(a, b);
|
|
36
|
+
if (e !== null)
|
|
37
|
+
return e;
|
|
38
|
+
const na = Number(a);
|
|
39
|
+
const nb = Number(b);
|
|
40
|
+
if (isNaN(na) || isNaN(nb))
|
|
41
|
+
return BaseColumnFormatter.stringCompare(a, b);
|
|
42
|
+
return na - nb;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static dateCompare(a: any, b: any): number
|
|
46
|
+
{
|
|
47
|
+
const e = BaseColumnFormatter.compareEmpty(a, b);
|
|
48
|
+
if (e !== null)
|
|
49
|
+
return e;
|
|
50
|
+
const ta = new Date(a).getTime();
|
|
51
|
+
const tb = new Date(b).getTime();
|
|
52
|
+
if (isNaN(ta) || isNaN(tb))
|
|
53
|
+
return BaseColumnFormatter.stringCompare(a, b);
|
|
54
|
+
return ta - tb;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static stringCompare(a: any, b: any): number
|
|
58
|
+
{
|
|
59
|
+
const e = BaseColumnFormatter.compareEmpty(a, b);
|
|
60
|
+
if (e !== null)
|
|
61
|
+
return e;
|
|
62
|
+
return String(a).localeCompare(String(b));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static smartCompare(a: any, b: any): number
|
|
66
|
+
{
|
|
67
|
+
const e = BaseColumnFormatter.compareEmpty(a, b);
|
|
68
|
+
if (e !== null)
|
|
69
|
+
return e;
|
|
70
|
+
const na = Number(a);
|
|
71
|
+
const nb = Number(b);
|
|
72
|
+
if (!isNaN(na) && !isNaN(nb))
|
|
73
|
+
return na - nb;
|
|
74
|
+
return String(a).localeCompare(String(b));
|
|
75
|
+
}
|
|
76
|
+
|
|
9
77
|
static getColumn(column: BaseMetaColumn, formatter: BaseColumnFormatter, group?: string, defaults?: { hidden?: boolean }): TableColumnInfo
|
|
10
78
|
{
|
|
11
79
|
return {
|
|
@@ -19,4 +19,8 @@ export class EmailFormatter extends BaseColumnFormatter
|
|
|
19
19
|
image: { url: "https://static.namirasoft.com/image/concept/type/email.png", alt: "phone" }
|
|
20
20
|
}, column, row, printable);
|
|
21
21
|
}
|
|
22
|
+
override compare(a: any, b: any): number
|
|
23
|
+
{
|
|
24
|
+
return BaseColumnFormatter.stringCompare(a, b);
|
|
25
|
+
}
|
|
22
26
|
}
|
|
@@ -11,4 +11,30 @@ export class IPFormatter extends BaseColumnFormatter
|
|
|
11
11
|
{
|
|
12
12
|
return value;
|
|
13
13
|
}
|
|
14
|
+
override compare(a: any, b: any): number
|
|
15
|
+
{
|
|
16
|
+
const e = BaseColumnFormatter.compareEmpty(a, b);
|
|
17
|
+
if (e !== null)
|
|
18
|
+
return e;
|
|
19
|
+
const parse = (v: any): number[] | null =>
|
|
20
|
+
{
|
|
21
|
+
const parts = String(v).split(".");
|
|
22
|
+
if (parts.length !== 4)
|
|
23
|
+
return null;
|
|
24
|
+
const nums = parts.map(p => Number(p));
|
|
25
|
+
if (nums.some(n => isNaN(n)))
|
|
26
|
+
return null;
|
|
27
|
+
return nums;
|
|
28
|
+
};
|
|
29
|
+
const na = parse(a);
|
|
30
|
+
const nb = parse(b);
|
|
31
|
+
if (na && nb)
|
|
32
|
+
{
|
|
33
|
+
for (let i = 0; i < 4; i++)
|
|
34
|
+
if (na[i] !== nb[i])
|
|
35
|
+
return na[i] - nb[i];
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
return BaseColumnFormatter.stringCompare(a, b);
|
|
39
|
+
}
|
|
14
40
|
}
|
|
@@ -56,4 +56,21 @@ export class JsonFormatter extends BaseColumnFormatter
|
|
|
56
56
|
return value;
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
override compare(a: any, b: any): number
|
|
60
|
+
{
|
|
61
|
+
const toText = (v: any) => typeof v === "string" ?
|
|
62
|
+
v :
|
|
63
|
+
(() =>
|
|
64
|
+
{
|
|
65
|
+
try
|
|
66
|
+
{
|
|
67
|
+
return JSON.stringify(v);
|
|
68
|
+
}
|
|
69
|
+
catch
|
|
70
|
+
{
|
|
71
|
+
return String(v);
|
|
72
|
+
}
|
|
73
|
+
})();
|
|
74
|
+
return BaseColumnFormatter.stringCompare(toText(a), toText(b));
|
|
75
|
+
}
|
|
59
76
|
}
|