namirasoft-site-react 1.4.403 → 1.4.404

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.
Files changed (299) hide show
  1. package/.dockerignore +86 -86
  2. package/.env.template +10 -10
  3. package/Dockerfile +18 -18
  4. package/config-overrides.js +72 -72
  5. package/dist/App.css +34 -0
  6. package/dist/components/NSBanner.module.css +47 -47
  7. package/dist/components/NSBarAction.module.css +84 -84
  8. package/dist/components/NSBarAlert.module.css +79 -79
  9. package/dist/components/NSBarNotification.module.css +34 -34
  10. package/dist/components/NSBarTitle.module.css +9 -9
  11. package/dist/components/NSBox.module.css +54 -54
  12. package/dist/components/NSBoxBaseCombo.module.css +6 -6
  13. package/dist/components/NSBoxBoolean.module.css +73 -73
  14. package/dist/components/NSBoxDate.module.css +4 -4
  15. package/dist/components/NSBoxDateTime.module.css +4 -4
  16. package/dist/components/NSBoxDuration.module.css +4 -4
  17. package/dist/components/NSBoxFile.module.css +10 -10
  18. package/dist/components/NSBoxPhone.module.css +35 -35
  19. package/dist/components/NSBoxRadio.module.css +33 -33
  20. package/dist/components/NSBoxSchemaBase.module.css +17 -17
  21. package/dist/components/NSBoxSchemaVariable.module.css +16 -16
  22. package/dist/components/NSBoxTextArea.module.css +12 -12
  23. package/dist/components/NSBoxTime.module.css +4 -4
  24. package/dist/components/NSButton.module.css +57 -57
  25. package/dist/components/NSButtonBlue.module.css +4 -4
  26. package/dist/components/NSButtonGreen.module.css +4 -4
  27. package/dist/components/NSButtonRed.module.css +4 -4
  28. package/dist/components/NSCard.module.css +114 -114
  29. package/dist/components/NSCardScreenshot.module.css +41 -41
  30. package/dist/components/NSChartColumn.module.css +7 -7
  31. package/dist/components/NSChartTable.module.css +21 -21
  32. package/dist/components/NSColumn.module.css +16 -16
  33. package/dist/components/NSCopyBox.module.css +39 -39
  34. package/dist/components/NSDialog.module.css +112 -112
  35. package/dist/components/NSDialogPageSelection.module.css +103 -103
  36. package/dist/components/NSDownTimer.module.css +55 -55
  37. package/dist/components/NSDownload.module.css +46 -46
  38. package/dist/components/NSElectronicCard.module.css +60 -60
  39. package/dist/components/NSEntityCardBackground.module.css +27 -27
  40. package/dist/components/NSFilterBox.module.css +27 -27
  41. package/dist/components/NSFilterBoxItems.module.css +15 -15
  42. package/dist/components/NSFilterItem.module.css +24 -24
  43. package/dist/components/NSFooter.module.css +134 -134
  44. package/dist/components/NSHeader.js +11 -6
  45. package/dist/components/NSHeader.js.map +1 -1
  46. package/dist/components/NSHeader.module.css +291 -291
  47. package/dist/components/NSHeaderScreenshot.module.css +35 -35
  48. package/dist/components/NSLabel.module.css +25 -25
  49. package/dist/components/NSLabelErrorNotifier.module.css +2 -2
  50. package/dist/components/NSLayout.module.css +14 -14
  51. package/dist/components/NSLine.module.css +15 -15
  52. package/dist/components/NSLink.module.css +36 -36
  53. package/dist/components/NSListGrouped.module.css +69 -69
  54. package/dist/components/NSLoading.module.css +38 -38
  55. package/dist/components/NSMenuAction.module.css +88 -88
  56. package/dist/components/NSMenuButton.module.css +44 -44
  57. package/dist/components/NSNoData.module.css +9 -9
  58. package/dist/components/NSPagination.module.css +85 -85
  59. package/dist/components/NSPanel.module.css +19 -19
  60. package/dist/components/NSPanelAccordion.module.css +4 -4
  61. package/dist/components/NSProductSearch.js +18 -7
  62. package/dist/components/NSProductSearch.js.map +1 -1
  63. package/dist/components/NSProductSearch.module.css +73 -68
  64. package/dist/components/NSRange.module.css +66 -66
  65. package/dist/components/NSRow.module.css +17 -17
  66. package/dist/components/NSSection.module.css +4 -4
  67. package/dist/components/NSSectionCards.module.css +38 -38
  68. package/dist/components/NSSectionTiles.module.css +10 -10
  69. package/dist/components/NSTabPage.module.css +59 -59
  70. package/dist/components/NSTable.module.css +263 -263
  71. package/dist/components/NSTile.module.css +76 -76
  72. package/dist/components/NSTimelineMonthly.module.css +71 -71
  73. package/dist/components/NSTitle.module.css +15 -15
  74. package/dist/index.css +6 -0
  75. package/dist/pages/NSNotFoundPage.module.css +18 -18
  76. package/dist/pages/NSUpdating.module.css +35 -35
  77. package/package.json +82 -82
  78. package/public/index.html +38 -38
  79. package/src/App.css +33 -33
  80. package/src/App.tsx +216 -216
  81. package/src/Color.tsx +10 -10
  82. package/src/CopyToClipboard.ts +6 -6
  83. package/src/NSBoxBuilder.tsx +912 -912
  84. package/src/ProductCacheService.ts +15 -15
  85. package/src/Validator.ts +166 -166
  86. package/src/components/INSBox.tsx +6 -6
  87. package/src/components/NSBanner.module.css +47 -47
  88. package/src/components/NSBanner.tsx +80 -80
  89. package/src/components/NSBarAction.module.css +84 -84
  90. package/src/components/NSBarAction.tsx +91 -91
  91. package/src/components/NSBarAlert.module.css +79 -79
  92. package/src/components/NSBarAlert.tsx +35 -35
  93. package/src/components/NSBarNotification.module.css +34 -34
  94. package/src/components/NSBarNotification.tsx +86 -86
  95. package/src/components/NSBarTitle.module.css +9 -9
  96. package/src/components/NSBarTitle.tsx +23 -23
  97. package/src/components/NSBox.module.css +54 -54
  98. package/src/components/NSBox.tsx +19 -19
  99. package/src/components/NSBoxBaseCombo.module.css +6 -6
  100. package/src/components/NSBoxBaseCombo.tsx +428 -428
  101. package/src/components/NSBoxBaseLayout.tsx +88 -88
  102. package/src/components/NSBoxBaseLayoutRecursive.tsx +54 -54
  103. package/src/components/NSBoxBoolean.module.css +73 -73
  104. package/src/components/NSBoxBoolean.tsx +128 -128
  105. package/src/components/NSBoxBooleans.tsx +178 -178
  106. package/src/components/NSBoxColor.tsx +95 -95
  107. package/src/components/NSBoxCombo.tsx +91 -91
  108. package/src/components/NSBoxDate.module.css +4 -4
  109. package/src/components/NSBoxDate.tsx +90 -90
  110. package/src/components/NSBoxDateTime.module.css +4 -4
  111. package/src/components/NSBoxDateTime.tsx +103 -103
  112. package/src/components/NSBoxDouble.tsx +94 -94
  113. package/src/components/NSBoxDuration.module.css +4 -4
  114. package/src/components/NSBoxDuration.tsx +95 -95
  115. package/src/components/NSBoxDynamic.tsx +67 -67
  116. package/src/components/NSBoxDynamics.tsx +68 -68
  117. package/src/components/NSBoxEmail.tsx +98 -98
  118. package/src/components/NSBoxEntity.tsx +174 -174
  119. package/src/components/NSBoxEnum.tsx +108 -108
  120. package/src/components/NSBoxFile.module.css +10 -10
  121. package/src/components/NSBoxFile.tsx +101 -101
  122. package/src/components/NSBoxFilePath.tsx +95 -95
  123. package/src/components/NSBoxFont.tsx +95 -95
  124. package/src/components/NSBoxIPV4.tsx +95 -95
  125. package/src/components/NSBoxIPV4Range.tsx +95 -95
  126. package/src/components/NSBoxIPV6.tsx +92 -92
  127. package/src/components/NSBoxIPV6Range.tsx +95 -95
  128. package/src/components/NSBoxInteger.tsx +91 -91
  129. package/src/components/NSBoxMoney.tsx +95 -95
  130. package/src/components/NSBoxPassword.tsx +108 -108
  131. package/src/components/NSBoxPhone.module.css +35 -35
  132. package/src/components/NSBoxPhone.tsx +107 -107
  133. package/src/components/NSBoxRadio.module.css +33 -33
  134. package/src/components/NSBoxRadio.tsx +91 -91
  135. package/src/components/NSBoxSchemaBase.module.css +17 -17
  136. package/src/components/NSBoxSchemaBase.tsx +540 -540
  137. package/src/components/NSBoxSchemaVariable.module.css +16 -16
  138. package/src/components/NSBoxSchemaVariable.tsx +247 -247
  139. package/src/components/NSBoxSearch.tsx +97 -97
  140. package/src/components/NSBoxString.tsx +93 -93
  141. package/src/components/NSBoxTextArea.module.css +12 -12
  142. package/src/components/NSBoxTextArea.tsx +98 -98
  143. package/src/components/NSBoxTime.module.css +4 -4
  144. package/src/components/NSBoxTime.tsx +93 -93
  145. package/src/components/NSBoxTimeZone.tsx +95 -95
  146. package/src/components/NSBoxURL.tsx +104 -104
  147. package/src/components/NSBoxVersion.tsx +95 -95
  148. package/src/components/NSButton.module.css +57 -57
  149. package/src/components/NSButton.tsx +75 -75
  150. package/src/components/NSButtonBlue.module.css +4 -4
  151. package/src/components/NSButtonBlue.tsx +29 -29
  152. package/src/components/NSButtonGreen.module.css +4 -4
  153. package/src/components/NSButtonGreen.tsx +29 -29
  154. package/src/components/NSButtonRed.module.css +4 -4
  155. package/src/components/NSButtonRed.tsx +29 -29
  156. package/src/components/NSCard.module.css +114 -114
  157. package/src/components/NSCard.tsx +63 -63
  158. package/src/components/NSCardScreenshot.module.css +41 -41
  159. package/src/components/NSCardScreenshot.tsx +31 -31
  160. package/src/components/NSChartColumn.module.css +7 -7
  161. package/src/components/NSChartColumn.tsx +106 -106
  162. package/src/components/NSChartDoughnut.tsx +112 -112
  163. package/src/components/NSChartPie.tsx +105 -105
  164. package/src/components/NSChartRange.tsx +14 -14
  165. package/src/components/NSChartTable.module.css +21 -21
  166. package/src/components/NSChartTable.tsx +94 -94
  167. package/src/components/NSColumn.module.css +16 -16
  168. package/src/components/NSColumn.tsx +24 -24
  169. package/src/components/NSCopy.tsx +58 -58
  170. package/src/components/NSCopyBox.module.css +39 -39
  171. package/src/components/NSCopyBox.tsx +53 -53
  172. package/src/components/NSDialog.module.css +112 -112
  173. package/src/components/NSDialog.tsx +61 -61
  174. package/src/components/NSDialogDelete.tsx +27 -27
  175. package/src/components/NSDialogInfo.tsx +49 -49
  176. package/src/components/NSDialogPageSelection.module.css +103 -103
  177. package/src/components/NSDialogPageSelection.tsx +234 -234
  178. package/src/components/NSDownTimer.module.css +55 -55
  179. package/src/components/NSDownTimer.tsx +91 -91
  180. package/src/components/NSDownload.module.css +46 -46
  181. package/src/components/NSDownload.tsx +69 -69
  182. package/src/components/NSElectronicCard.module.css +60 -60
  183. package/src/components/NSElectronicCard.tsx +46 -46
  184. package/src/components/NSEntityCardBackground.module.css +27 -27
  185. package/src/components/NSEntityCardBackground.tsx +36 -36
  186. package/src/components/NSFilterBox.module.css +27 -27
  187. package/src/components/NSFilterBox.tsx +477 -477
  188. package/src/components/NSFilterBoxItems.module.css +15 -15
  189. package/src/components/NSFilterBoxItems.tsx +52 -52
  190. package/src/components/NSFilterItem.module.css +24 -24
  191. package/src/components/NSFilterItem.tsx +27 -27
  192. package/src/components/NSFooter.module.css +134 -134
  193. package/src/components/NSFooter.tsx +321 -321
  194. package/src/components/NSHeader.module.css +291 -291
  195. package/src/components/NSHeader.tsx +314 -309
  196. package/src/components/NSHeaderScreenshot.module.css +35 -35
  197. package/src/components/NSHeaderScreenshot.tsx +39 -39
  198. package/src/components/NSID.tsx +158 -158
  199. package/src/components/NSLabel.module.css +25 -25
  200. package/src/components/NSLabel.tsx +47 -47
  201. package/src/components/NSLabelErrorNotifier.module.css +2 -2
  202. package/src/components/NSLabelErrorNotifier.tsx +35 -35
  203. package/src/components/NSLayout.module.css +14 -14
  204. package/src/components/NSLayout.tsx +134 -134
  205. package/src/components/NSLine.module.css +15 -15
  206. package/src/components/NSLine.tsx +13 -13
  207. package/src/components/NSLink.module.css +36 -36
  208. package/src/components/NSLink.tsx +25 -25
  209. package/src/components/NSLinkBlue.tsx +21 -21
  210. package/src/components/NSLinkGreen.tsx +12 -12
  211. package/src/components/NSLinkRed.tsx +12 -12
  212. package/src/components/NSListGrouped.module.css +69 -69
  213. package/src/components/NSListGrouped.tsx +106 -106
  214. package/src/components/NSListProduct.tsx +44 -44
  215. package/src/components/NSLoading.module.css +38 -38
  216. package/src/components/NSLoading.tsx +37 -37
  217. package/src/components/NSMenuAction.module.css +88 -88
  218. package/src/components/NSMenuAction.tsx +106 -106
  219. package/src/components/NSMenuButton.module.css +44 -44
  220. package/src/components/NSMenuButton.tsx +206 -206
  221. package/src/components/NSNoData.module.css +9 -9
  222. package/src/components/NSNoData.tsx +24 -24
  223. package/src/components/NSPagination.module.css +85 -85
  224. package/src/components/NSPagination.tsx +182 -182
  225. package/src/components/NSPanel.module.css +19 -19
  226. package/src/components/NSPanel.tsx +24 -24
  227. package/src/components/NSPanelAccordion.module.css +4 -4
  228. package/src/components/NSPanelAccordion.tsx +51 -51
  229. package/src/components/NSProductSearch.module.css +73 -68
  230. package/src/components/NSProductSearch.tsx +193 -155
  231. package/src/components/NSRange.module.css +66 -66
  232. package/src/components/NSRange.tsx +83 -83
  233. package/src/components/NSRepeater.tsx +254 -254
  234. package/src/components/NSRepeaterNSBoxSchemaVariable.tsx +90 -90
  235. package/src/components/NSRepeaterNSTag.tsx +82 -82
  236. package/src/components/NSRow.module.css +17 -17
  237. package/src/components/NSRow.tsx +24 -24
  238. package/src/components/NSSection.module.css +4 -4
  239. package/src/components/NSSection.tsx +26 -26
  240. package/src/components/NSSectionCards.module.css +38 -38
  241. package/src/components/NSSectionCards.tsx +51 -51
  242. package/src/components/NSSectionTiles.module.css +10 -10
  243. package/src/components/NSSectionTiles.tsx +25 -25
  244. package/src/components/NSSectionTitle.tsx +21 -21
  245. package/src/components/NSSpace.tsx +28 -28
  246. package/src/components/NSTabPage.module.css +59 -59
  247. package/src/components/NSTabPage.tsx +91 -91
  248. package/src/components/NSTable.module.css +263 -263
  249. package/src/components/NSTable.tsx +636 -636
  250. package/src/components/NSTag.tsx +74 -74
  251. package/src/components/NSTile.module.css +76 -76
  252. package/src/components/NSTile.tsx +27 -27
  253. package/src/components/NSTimelineMonthly.module.css +71 -71
  254. package/src/components/NSTimelineMonthly.tsx +44 -44
  255. package/src/components/NSTitle.module.css +15 -15
  256. package/src/components/NSTitle.tsx +19 -19
  257. package/src/formatter/BackColorFormatter.tsx +23 -23
  258. package/src/formatter/BaseColumnFormatter.ts +16 -16
  259. package/src/formatter/BaseURLImageFormatter.tsx +33 -33
  260. package/src/formatter/BooleanFormatter.ts +22 -22
  261. package/src/formatter/DateFormatter.ts +21 -21
  262. package/src/formatter/DateTimeFormatter.ts +21 -21
  263. package/src/formatter/DurationFormatter.ts +13 -13
  264. package/src/formatter/EmailFormatter.tsx +21 -21
  265. package/src/formatter/EnumFormatter.ts +13 -13
  266. package/src/formatter/FloatFormatter.ts +23 -23
  267. package/src/formatter/ForeColorFormatter.tsx +24 -24
  268. package/src/formatter/IDFormatter.tsx +30 -30
  269. package/src/formatter/IPFormatter.ts +13 -13
  270. package/src/formatter/IntegerFormatter.ts +23 -23
  271. package/src/formatter/JsonFormatter.ts +21 -21
  272. package/src/formatter/MoneyFormatter.ts +35 -35
  273. package/src/formatter/PhoneFormatter.tsx +21 -21
  274. package/src/formatter/StringFormatter.tsx +43 -43
  275. package/src/formatter/TimeFormatter.ts +21 -21
  276. package/src/formatter/URLFormatter.tsx +21 -21
  277. package/src/formatter/UnknowFormatter.ts +18 -18
  278. package/src/index.tsx +7 -7
  279. package/src/main.ts +225 -225
  280. package/src/pages/NSNotFoundPage.module.css +18 -18
  281. package/src/pages/NSNotFoundPage.tsx +11 -11
  282. package/src/pages/NSUpdating.module.css +35 -35
  283. package/src/pages/NSUpdating.tsx +32 -32
  284. package/src/props/IBackgroundProps.ts +5 -5
  285. package/src/props/IBaseComponentProps.ts +8 -8
  286. package/src/props/IHeaderIconProps.ts +10 -10
  287. package/src/props/IHeaderLeftProps.ts +6 -6
  288. package/src/props/IHeaderRightProps.ts +6 -6
  289. package/src/props/IImageProps.ts +4 -4
  290. package/src/props/ILinkProps.ts +5 -5
  291. package/src/props/IValidationNumberProps.ts +4 -4
  292. package/src/props/IValidationPrecisionProps.ts +3 -3
  293. package/src/props/IValidationProps.ts +9 -9
  294. package/src/props/IValidationRegexProps.ts +4 -4
  295. package/src/props/IValidationStringProps.ts +4 -4
  296. package/src/routing/NSNotifier.ts +114 -114
  297. package/src/routing/NSRouterMaker.tsx +20 -20
  298. package/src/routing/NSRouterMakerComponent.ts +5 -5
  299. package/src/routing/NSRouterMakerProps.ts +5 -5
@@ -1,637 +1,637 @@
1
- "use client";
2
- import React from "react";
3
- import { Component } from 'react';
4
- import { writeFile, utils } from 'xlsx';
5
- import { NSButton } from './NSButton';
6
- import { NSPagination } from './NSPagination';
7
- import { NSDialogInfo } from './NSDialogInfo';
8
- import { NSSpace, NSSpaceSizeType } from './NSSpace';
9
- import { NSDialogPageSelection } from './NSDialogPageSelection';
10
- import { NSLoading } from './NSLoading';
11
- import { NSNoData } from './NSNoData';
12
- import { IBaseComponentProps } from "../props/IBaseComponentProps";
13
- import { BaseColumnFormatter } from '../formatter/BaseColumnFormatter';
14
- import Styles from './NSTable.module.css';
15
- import { BaseMetaColumn, BaseMetaTable, IStorageLocal, SortItem } from "namirasoft-core";
16
-
17
- export interface TableInfo
18
- {
19
- name: string;
20
- text: string;
21
- }
22
-
23
- export interface TableColumnInfo
24
- {
25
- table: TableInfo;
26
- index: number;
27
- name: string;
28
- text: string;
29
- formatter: BaseColumnFormatter;
30
- }
31
-
32
- export interface TableRowInfo<RowType>
33
- {
34
- index: number;
35
- value: RowType;
36
- }
37
-
38
- export interface TableCellInfo<RowType>
39
- {
40
- column: TableColumnInfo;
41
- row: TableRowInfo<RowType>;
42
- value: any;
43
- formatted: any;
44
- }
45
-
46
- export interface NSTableProps<RowType> extends IBaseComponentProps
47
- {
48
- name: string;
49
- checkbox: boolean;
50
- columns: TableColumnInfo[];
51
- getRows: (page: number, size: number, sorts: SortItem[]) => Promise<{ rows: RowType[], count: number }>;
52
- getRowKey: (row: TableRowInfo<RowType>) => string;
53
- getRowAttributes?: (row_value: RowType, row_index: number) => { [key: string]: any };
54
- getColumnAttributes?: (column: TableColumnInfo) => { [key: string]: any };
55
- getCellFormattedValue?: (value: any, column: TableColumnInfo, row: TableRowInfo<RowType>, printable: boolean) => any;
56
- onColumnClick?: (e: React.MouseEvent<HTMLTableDataCellElement, MouseEvent>, column: TableColumnInfo) => void;
57
- onRowClick?: (e: React.MouseEvent<HTMLTableRowElement, MouseEvent>, row: TableRowInfo<RowType>) => void;
58
- onCellClick?: (e: React.MouseEvent<HTMLTableDataCellElement, MouseEvent>, cell: TableCellInfo<RowType>) => boolean | undefined;
59
- onSelectedIDsChanged?: () => void;
60
- onSortChanged?: (items: SortItem[] | null) => void;
61
- onVisibleColumnsChanged?: (visible_columns: { table: string, column: string }[]) => void;
62
- ui?: {
63
- pagination?: boolean;
64
- };
65
- }
66
-
67
- interface NSTableState<RowType>
68
- {
69
- columns: TableColumnInfo[];
70
- visible_columns: { table: string, column: string }[];
71
- totalItems: number;
72
- rows: RowType[] | null;
73
- title?: string;
74
- model: {
75
- show: boolean;
76
- description?: string;
77
- };
78
- selectedIDs: string[];
79
- selectedRows: RowType[];
80
- pageSelectionMode: PageSelectionMode;
81
- sortItems: SortItem[] | null;
82
- }
83
-
84
- enum PageSelectionMode
85
- {
86
- Hidden = "Hidden",
87
- Print = "Print",
88
- CSV = "CSV"
89
- }
90
-
91
- export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableState<RowType>>
92
- {
93
- private nstable_top_div = React.createRef<HTMLDivElement>();
94
- NSPagination = React.createRef<NSPagination>();
95
- constructor(props: NSTableProps<RowType>)
96
- {
97
- super(props);
98
- this.state = {
99
- columns: props.columns,
100
- visible_columns: this.getVisibleColumns(),
101
- rows: null,
102
- totalItems: 0,
103
- model: { show: false },
104
- selectedIDs: [],
105
- selectedRows: [],
106
- pageSelectionMode: PageSelectionMode.Hidden,
107
- sortItems: this.getSortItems(),
108
- };
109
- this.getSortItemsKey = this.getSortItemsKey.bind(this);
110
- this.getSortItems = this.getSortItems.bind(this);
111
- this.setSortItems = this.setSortItems.bind(this);
112
- this.getVisibleColumnsKey = this.getVisibleColumnsKey.bind(this);
113
- this.getVisibleColumns = this.getVisibleColumns.bind(this);
114
- this.setVisibleColumns = this.setVisibleColumns.bind(this);
115
- this.setColumns = this.setColumns.bind(this);
116
- this.setColumns = this.setColumns.bind(this);
117
- this.setRows = this.setRows.bind(this);
118
- this.foreachColumn = this.foreachColumn.bind(this);
119
- this.getColumns = this.getColumns.bind(this);
120
- this.showModal = this.showModal.bind(this);
121
- this.hideModal = this.hideModal.bind(this);
122
- this.onPageChange = this.onPageChange.bind(this);
123
- this.isSomeChecked = this.isSomeChecked.bind(this);
124
- this.toggleAllCheckboxes = this.toggleAllCheckboxes.bind(this);
125
- this.print = this.print.bind(this);
126
- this.exportCSV = this.exportCSV.bind(this);
127
- this.isAllChecked = this.isAllChecked.bind(this);
128
- this.reload = this.reload.bind(this);
129
- }
130
- private getSortItemsKey(): string
131
- {
132
- return "ns_table_" + this.props.name + "_sort_items";
133
- }
134
- getSortItems(): SortItem[]
135
- {
136
- let storage = new IStorageLocal();
137
- let item = storage.get(this.getSortItemsKey(), "");
138
- try
139
- {
140
- return SortItem.parse(item);
141
- } catch (error)
142
- {
143
- }
144
- return [];
145
- }
146
- setSortItems(items: SortItem[] | null)
147
- {
148
- let storage = new IStorageLocal();
149
- storage.set(this.getSortItemsKey(), SortItem.stringify(items));
150
- this.setState({ sortItems: items }, () =>
151
- {
152
- this.props.onSortChanged?.(items);
153
- this.reload(null, null);
154
- });
155
- }
156
- private getVisibleColumnsKey(): string
157
- {
158
- return "ns_table_" + this.props.name + "_visible_columns";
159
- }
160
- getVisibleColumns(): { table: string, column: string }[]
161
- {
162
- let storage = new IStorageLocal();
163
- let item = storage.get(this.getVisibleColumnsKey(), "");
164
- try
165
- {
166
- return JSON.parse(item);
167
- } catch (error)
168
- {
169
- }
170
- return [];
171
- }
172
- setVisibleColumns(visible_columns: { table: string, column: string }[])
173
- {
174
- let storage = new IStorageLocal();
175
- storage.set(this.getVisibleColumnsKey(), JSON.stringify(visible_columns));
176
- this.setState({ visible_columns }, () =>
177
- {
178
- this.props.onVisibleColumnsChanged?.(visible_columns);
179
- });
180
- }
181
- setColumns(columns: TableColumnInfo[])
182
- {
183
- this.setState({ columns });
184
- }
185
- setRows(rows: RowType[] | null, totalItems: number)
186
- {
187
- this.setState({ rows, totalItems }, () =>
188
- {
189
- this.nstable_top_div.current?.scrollIntoView({ behavior: 'smooth', block: 'center' });
190
- });
191
- }
192
- foreachColumn(visible: boolean | null, handler: (column: TableColumnInfo) => void)
193
- {
194
- let vs = this.getVisibleColumns();
195
- let shouldBeVisible = (c: TableColumnInfo) =>
196
- {
197
- if (vs.length === 0)
198
- return true;
199
- return vs.filter(v => v.table === c.table.name && v.column === c.name).length > 0;
200
- };
201
- this.state.columns.forEach(c =>
202
- {
203
- if (visible === null || shouldBeVisible(c) === visible)
204
- handler(c);
205
- })
206
- }
207
- getColumns(visible: boolean | null): TableColumnInfo[]
208
- {
209
- let columns: TableColumnInfo[] = [];
210
- this.foreachColumn(visible, c => columns.push(c));
211
- return columns;
212
- }
213
- private showModal(description: string, title?: string)
214
- {
215
- this.setState({ model: { show: true, description }, title });
216
- }
217
- private hideModal()
218
- {
219
- this.setState({ model: { show: false } });
220
- }
221
- private onPageChange(page: number, size: number)
222
- {
223
- this.reload(page, size);
224
- }
225
- public async reload(page: number | null, size: number | null)
226
- {
227
- this.setRows(null, 0);
228
- if (page === null)
229
- page = this.NSPagination.current?.getCurrentPage() ?? 0;
230
- if (size === null)
231
- size = this.NSPagination.current?.getPageSize() ?? 0;
232
- try
233
- {
234
- let sorts = this.getSortItems();
235
- let res = await this.props.getRows(page, size, sorts);
236
- this.setRows(res.rows, res.count);
237
- } catch (error)
238
- {
239
- }
240
- }
241
- private toggleAllCheckboxes()
242
- {
243
- let selectedIDs: string[] = [];
244
- let selectedRows: RowType[] = [];
245
- if (this.getSelectedIDs().length === 0)
246
- this.state.rows?.forEach((row, rowIndex) =>
247
- {
248
- let id = this.props.getRowKey({ index: rowIndex, value: row });
249
- selectedIDs.push(id);
250
- selectedRows.push(row);
251
- })
252
- this.setSelectedIDs(selectedIDs, selectedRows);
253
- }
254
- print(rows: RowType[])
255
- {
256
- const printWindow = window.open('', '', 'height=500,width=800');
257
- printWindow!.document.write(`<html><head><title>${this.props.name}</title>`);
258
- printWindow!.document.write('<style>table { width: 100%; border-collapse: collapse; } th, td { border: 1px solid black; padding: 8px; text-align: left; }</style>');
259
- printWindow!.document.write('</head><body>');
260
- printWindow!.document.write('<table>');
261
- printWindow!.document.write('<thead><tr>');
262
-
263
- this.foreachColumn(true, column =>
264
- {
265
- printWindow!.document.write('<th>' + column.text + '</th>');
266
- });
267
-
268
- printWindow!.document.write('</tr></thead><tbody>');
269
-
270
- // Add table rows
271
- rows.forEach((rowValue, rowIndex) =>
272
- {
273
- let row = { index: rowIndex, value: rowValue };
274
- printWindow!.document.write('<tr>');
275
- this.foreachColumn(true, column =>
276
- {
277
- let cell = this.getCellTableInfo(column, row, true);
278
- printWindow!.document.write('<td>' + (cell.formatted ?? "") + '</td>');
279
- });
280
- printWindow!.document.write('</tr>');
281
- });
282
-
283
- printWindow!.document.write('</tbody></table>');
284
- printWindow!.document.write('</body></html>');
285
- printWindow!.document.close();
286
- printWindow!.print();
287
- }
288
- exportCSV(rows: RowType[])
289
- {
290
- const worksheet = utils.json_to_sheet(rows || []);
291
- const workbook = utils.book_new();
292
- utils.book_append_sheet(workbook, worksheet, this.props.name);
293
- writeFile(workbook, this.props.name + ".xlsx");
294
- }
295
- getSelectedIDs(): string[]
296
- {
297
- return this.state.selectedIDs;
298
- }
299
- getSelectedRows(): RowType[]
300
- {
301
- return this.state.selectedRows;
302
- }
303
- setSelectedIDs(ids: string[], rows: RowType[], callback?: () => void)
304
- {
305
- this.setState({ selectedIDs: ids, selectedRows: rows }, () =>
306
- {
307
- if (this.props.onSelectedIDsChanged)
308
- this.props.onSelectedIDsChanged();
309
- if (callback)
310
- callback();
311
- });
312
- }
313
- private isAllChecked(): boolean
314
- {
315
- return this.state.rows !== null && this.state.rows.length > 0 && this.state.selectedIDs.length === this.state.rows.length;
316
- }
317
-
318
- private isSomeChecked(): boolean
319
- {
320
- return this.state.selectedIDs.length > 0 && !this.isAllChecked();
321
- }
322
-
323
- private getCellTableInfo(column: TableColumnInfo, row: TableRowInfo<RowType>, printable: boolean)
324
- {
325
- let value = (row.value as any)[column.name];
326
- let formatted = this.getCellFormattedValue(value, column, row, printable);
327
- return { column, row, value, formatted };
328
- }
329
- private getCellFormattedValue(value: any, column: TableColumnInfo, row: TableRowInfo<RowType>, printable: boolean)
330
- {
331
- if (this.props.getCellFormattedValue)
332
- return this.props.getCellFormattedValue(value, column, row, printable);
333
- return column.formatter.format(value, column, row, printable);
334
- }
335
- override componentDidMount(): void
336
- {
337
- if (!this.NSPagination.current)
338
- this.reload(null, null);
339
- }
340
- override render()
341
- {
342
- let getRowAttributes = (row_value: RowType, row_index: number) =>
343
- {
344
- if (this.props.getRowAttributes)
345
- return this.props.getRowAttributes(row_value, row_index);
346
- return {};
347
- }
348
- let getColumnAttributes = (column: TableColumnInfo) =>
349
- {
350
- if (this.props.getColumnAttributes)
351
- return this.props.getColumnAttributes(column);
352
- return {};
353
- }
354
- let onColumnClick = (e: React.MouseEvent<HTMLTableDataCellElement, MouseEvent>, column: TableColumnInfo) =>
355
- {
356
- if (this.props.onColumnClick)
357
- this.props.onColumnClick(e, column);
358
- }
359
- let onRowClick = (e: React.MouseEvent<HTMLTableRowElement, MouseEvent>, row: TableRowInfo<RowType>) =>
360
- {
361
- if (this.props.onRowClick)
362
- this.props.onRowClick(e, row);
363
- };
364
- let onCellClick = (e: React.MouseEvent<HTMLTableDataCellElement, MouseEvent>, cell: TableCellInfo<RowType>) =>
365
- {
366
- let overided = cell.column.formatter.onclick_overrided;
367
- if (this.props.onCellClick)
368
- overided = this.props.onCellClick(e, cell) ?? true;
369
- if (!overided)
370
- this.showModal(cell.formatted, cell.column.text);
371
- };
372
- let content;
373
- if (this.state.rows === null)
374
- {
375
- content = (
376
- <tr className="d-flex justify-content-center align-items-center p-0">
377
- <td className="w-100 h-100 m-0 mh-100">
378
- <NSLoading />
379
- </td>
380
- </tr>
381
- );
382
- }
383
- else if (this.state.rows.length === 0)
384
- {
385
- content = (
386
- <tr className="d-flex justify-content-center align-items-center p-0">
387
- <td className="w-100 h-100 m-0 mh-100">
388
- <NSNoData lable='No Data' classList={["p-3"]} />
389
- </td>
390
- </tr>
391
- );
392
- }
393
- else
394
- {
395
- content = this.state.rows.map((rowValue, rowIndex) =>
396
- {
397
- let row = { index: rowIndex, value: rowValue };
398
- return <tr
399
- key={this.props.getRowKey(row)}
400
- {...getRowAttributes(rowValue, rowIndex)}
401
- onClick={(e) => { onRowClick(e, row); }}
402
- >
403
- {
404
- this.props.checkbox &&
405
- <td>
406
- <label
407
- htmlFor={`checkbox_device_${this.props.getRowKey(row)}`}
408
- className={Styles.ns_check_box_label}
409
- >
410
- <input
411
- id={`checkbox_device_${this.props.getRowKey(row)}`}
412
- type="checkbox"
413
- className={Styles.ns_check_box}
414
- checked={this.state.selectedIDs.includes(this.props.getRowKey(row))}
415
- onChange={(e) =>
416
- {
417
- let selectedIDs = this.state.selectedIDs;
418
- let selectedRows = this.state.selectedRows;
419
- let id = this.props.getRowKey(row);
420
- if (e.currentTarget.checked)
421
- {
422
- selectedIDs.push(id);
423
- selectedRows.push(row.value);
424
- }
425
- else
426
- {
427
- selectedIDs = selectedIDs.filter(x => x !== id);
428
- selectedRows = selectedRows.filter(x => this.props.getRowKey({ index: -1, value: x }) !== id);
429
- }
430
- this.setSelectedIDs(selectedIDs, selectedRows);
431
- }}
432
- />
433
- </label>
434
- </td>
435
- }
436
- {
437
- this.getColumns(true).map((column, index) =>
438
- {
439
- column.index = index + (this.props.checkbox ? 1 : 0);
440
- let cell = this.getCellTableInfo(column, row, false);
441
- return (
442
- <td className='py-3' width={column.formatter.width} {...getColumnAttributes(column)} key={column.index} data-label={`${column.text}: `} onClick={(e) =>
443
- {
444
- onColumnClick(e, column);
445
- onCellClick(e, cell);
446
- }}>
447
-
448
- {
449
- cell.formatted ?? ""
450
- }
451
- </td>
452
- );
453
- })
454
- }
455
- </tr>
456
- });
457
- }
458
- let getSortSign = (column: TableColumnInfo) =>
459
- {
460
- if (this.state.sortItems)
461
- {
462
- let c = this.state.sortItems.filter(c => c.table.name === column.table.name && c.column.name === column.name)[0]
463
- if (c)
464
- {
465
- if (c.ascending)
466
- return "↑"
467
- return "↓";
468
- }
469
- }
470
- return "";
471
- };
472
-
473
- return (
474
- <>
475
- <div ref={this.nstable_top_div} />
476
- <div
477
- id={this.props.id}
478
- className={this.props.classList?.join(" ") ?? ""}
479
- style={this.props.style}
480
- >
481
- <table className={Styles.ns_table} >
482
- <thead>
483
- <tr>
484
- {
485
- this.props.checkbox &&
486
- <th style={{ width: "24px", height: "24px" }}>
487
- <label
488
- htmlFor='checkbox'
489
- className={Styles.ns_checkbox_label}
490
- >
491
- <input
492
- id="checkbox"
493
- type="checkbox"
494
- className={`${Styles.ns_check_box} ${this.isSomeChecked() ? Styles.ns_indeterminate : ""}`}
495
- checked={this.getSelectedIDs().length > 0}
496
- onChange={this.toggleAllCheckboxes}
497
- ></input>
498
- </label>
499
- </th>
500
- }
501
- {
502
- this.getColumns(true).map(column => <th
503
- key={column.name}
504
- scope="col"
505
- style={{ width: column.formatter.width, cursor: "pointer" }}
506
- onClick={() =>
507
- {
508
- let t = new BaseMetaTable(null, column.table.name, column.table.text);
509
- let c = new BaseMetaColumn(t, column.name, column.text, "", false);
510
- let items = this.getSortItems();
511
- if (!items || items.length === 0 || items[0].table.name !== t.name || items[0].column.name !== c.name)
512
- this.setSortItems([new SortItem(t, c, true)]);
513
- else
514
- {
515
- if (items[0].ascending)
516
- this.setSortItems([new SortItem(t, c, false)]);
517
- else
518
- this.setSortItems(null);
519
- }
520
- }}
521
- >
522
- {
523
- column.text + " " + getSortSign(column)
524
- }
525
- </th>)
526
- }
527
- </tr>
528
- </thead>
529
- <tbody className={Styles.ns_tbody}>
530
- {content}
531
- </tbody>
532
- </table>
533
- <NSSpace size={NSSpaceSizeType.MINI} />
534
- <section className={Styles.ns_table_footer}>
535
- {
536
- (this.props.ui?.pagination ?? true) &&
537
- <NSPagination ref={this.NSPagination} totalItems={this.state.totalItems} onPageChange={this.onPageChange} />
538
- }
539
- <NSSpace size={NSSpaceSizeType.MINI} classList={["d-lg-none"]} />
540
- <div className={Styles.ns_button_panel}>
541
- {
542
- this.state.pageSelectionMode !== PageSelectionMode.Hidden &&
543
- <NSDialogPageSelection<RowType>
544
- icon={
545
- this.state.pageSelectionMode === PageSelectionMode.Print ? "https://static.namirasoft.com/image/concept/print/blue.svg" :
546
- this.state.pageSelectionMode === PageSelectionMode.CSV ? "https://static.namirasoft.com/image/concept/export/blue.svg" : ""
547
- }
548
- current_page={this.NSPagination.current?.getCurrentPage() ?? 1}
549
- current_size={this.NSPagination.current?.getPageSize() ?? 0}
550
- max_page={1}
551
- getItems={async (page, size, selected) =>
552
- {
553
- if (selected)
554
- {
555
- let rows: RowType[] = [];
556
- if (this.state.rows)
557
- for (let i = 0; i < this.state.rows.length; i++)
558
- {
559
- const row = { index: i, value: this.state.rows[i] };
560
- let id = this.props.getRowKey(row);
561
- if (this.state.selectedIDs.includes(id))
562
- rows.push(row.value);
563
- }
564
- return rows;
565
- }
566
- let res = await this.props.getRows(page, size, this.getSortItems());
567
- return res.rows;
568
- }}
569
- onFinish={async (items: RowType[]) =>
570
- {
571
- if (this.state.pageSelectionMode === PageSelectionMode.Print)
572
- this.print(items);
573
- else if (this.state.pageSelectionMode === PageSelectionMode.CSV)
574
- this.exportCSV(items);
575
- }}
576
- onClose={() => { this.setState({ pageSelectionMode: PageSelectionMode.Hidden }); }
577
- }
578
- />
579
- }
580
- <NSButton
581
- title='Chart'
582
- icon={{ src: "https://static.namirasoft.com/image/concept/chart/blue.svg" }}
583
- onClick={{
584
- action: () =>
585
- {
586
- this.showModal(" ", "This feature will be available soon in upcoming versions.");
587
- },
588
- showLoading: false
589
- }}
590
- style={{ border: '1px solid rgba(255, 148, 50, 1)', width: "128px" }}
591
- />
592
- <NSButton
593
- title='Print'
594
- icon={{ src: "https://static.namirasoft.com/image/concept/print/blue.svg" }}
595
- onClick={{
596
- action: () => { this.setState({ pageSelectionMode: PageSelectionMode.Print }); },
597
- showLoading: false
598
- }}
599
- style={{ border: '1px solid rgba(255, 148, 50, 1)', width: "128px" }}
600
- />
601
- <NSButton
602
- title='Export'
603
- icon={{ src: "https://static.namirasoft.com/image/concept/export/blue.svg" }}
604
- onClick={{
605
- action: () => { this.setState({ pageSelectionMode: PageSelectionMode.CSV }); },
606
- showLoading: false
607
- }}
608
- style={{ border: '1px solid rgba(255, 148, 50, 1)', width: "128px" }}
609
- />
610
- <NSButton
611
- title='Refresh'
612
- icon={{ src: "https://static.namirasoft.com/image/concept/refresh/blue.svg" }}
613
- onClick={{
614
- action: async (onFinished) =>
615
- {
616
- this.reload(null, null).then(onFinished).catch(onFinished);
617
- }
618
- }}
619
- style={{ border: '1px solid rgba(3, 119, 255, 1)', width: "128px" }} />
620
- </div>
621
- </section>
622
- {
623
- this.state.model.show &&
624
- <NSDialogInfo
625
- description={this.state.model.description}
626
- onClose={() => { this.hideModal(); }}
627
- title={this.state.title}
628
- show_as_code={true}
629
- >
630
- <></>
631
- </NSDialogInfo>
632
- }
633
- </div >
634
- </>
635
- );
636
- }
1
+ "use client";
2
+ import React from "react";
3
+ import { Component } from 'react';
4
+ import { writeFile, utils } from 'xlsx';
5
+ import { NSButton } from './NSButton';
6
+ import { NSPagination } from './NSPagination';
7
+ import { NSDialogInfo } from './NSDialogInfo';
8
+ import { NSSpace, NSSpaceSizeType } from './NSSpace';
9
+ import { NSDialogPageSelection } from './NSDialogPageSelection';
10
+ import { NSLoading } from './NSLoading';
11
+ import { NSNoData } from './NSNoData';
12
+ import { IBaseComponentProps } from "../props/IBaseComponentProps";
13
+ import { BaseColumnFormatter } from '../formatter/BaseColumnFormatter';
14
+ import Styles from './NSTable.module.css';
15
+ import { BaseMetaColumn, BaseMetaTable, IStorageLocal, SortItem } from "namirasoft-core";
16
+
17
+ export interface TableInfo
18
+ {
19
+ name: string;
20
+ text: string;
21
+ }
22
+
23
+ export interface TableColumnInfo
24
+ {
25
+ table: TableInfo;
26
+ index: number;
27
+ name: string;
28
+ text: string;
29
+ formatter: BaseColumnFormatter;
30
+ }
31
+
32
+ export interface TableRowInfo<RowType>
33
+ {
34
+ index: number;
35
+ value: RowType;
36
+ }
37
+
38
+ export interface TableCellInfo<RowType>
39
+ {
40
+ column: TableColumnInfo;
41
+ row: TableRowInfo<RowType>;
42
+ value: any;
43
+ formatted: any;
44
+ }
45
+
46
+ export interface NSTableProps<RowType> extends IBaseComponentProps
47
+ {
48
+ name: string;
49
+ checkbox: boolean;
50
+ columns: TableColumnInfo[];
51
+ getRows: (page: number, size: number, sorts: SortItem[]) => Promise<{ rows: RowType[], count: number }>;
52
+ getRowKey: (row: TableRowInfo<RowType>) => string;
53
+ getRowAttributes?: (row_value: RowType, row_index: number) => { [key: string]: any };
54
+ getColumnAttributes?: (column: TableColumnInfo) => { [key: string]: any };
55
+ getCellFormattedValue?: (value: any, column: TableColumnInfo, row: TableRowInfo<RowType>, printable: boolean) => any;
56
+ onColumnClick?: (e: React.MouseEvent<HTMLTableDataCellElement, MouseEvent>, column: TableColumnInfo) => void;
57
+ onRowClick?: (e: React.MouseEvent<HTMLTableRowElement, MouseEvent>, row: TableRowInfo<RowType>) => void;
58
+ onCellClick?: (e: React.MouseEvent<HTMLTableDataCellElement, MouseEvent>, cell: TableCellInfo<RowType>) => boolean | undefined;
59
+ onSelectedIDsChanged?: () => void;
60
+ onSortChanged?: (items: SortItem[] | null) => void;
61
+ onVisibleColumnsChanged?: (visible_columns: { table: string, column: string }[]) => void;
62
+ ui?: {
63
+ pagination?: boolean;
64
+ };
65
+ }
66
+
67
+ interface NSTableState<RowType>
68
+ {
69
+ columns: TableColumnInfo[];
70
+ visible_columns: { table: string, column: string }[];
71
+ totalItems: number;
72
+ rows: RowType[] | null;
73
+ title?: string;
74
+ model: {
75
+ show: boolean;
76
+ description?: string;
77
+ };
78
+ selectedIDs: string[];
79
+ selectedRows: RowType[];
80
+ pageSelectionMode: PageSelectionMode;
81
+ sortItems: SortItem[] | null;
82
+ }
83
+
84
+ enum PageSelectionMode
85
+ {
86
+ Hidden = "Hidden",
87
+ Print = "Print",
88
+ CSV = "CSV"
89
+ }
90
+
91
+ export class NSTable<RowType> extends Component<NSTableProps<RowType>, NSTableState<RowType>>
92
+ {
93
+ private nstable_top_div = React.createRef<HTMLDivElement>();
94
+ NSPagination = React.createRef<NSPagination>();
95
+ constructor(props: NSTableProps<RowType>)
96
+ {
97
+ super(props);
98
+ this.state = {
99
+ columns: props.columns,
100
+ visible_columns: this.getVisibleColumns(),
101
+ rows: null,
102
+ totalItems: 0,
103
+ model: { show: false },
104
+ selectedIDs: [],
105
+ selectedRows: [],
106
+ pageSelectionMode: PageSelectionMode.Hidden,
107
+ sortItems: this.getSortItems(),
108
+ };
109
+ this.getSortItemsKey = this.getSortItemsKey.bind(this);
110
+ this.getSortItems = this.getSortItems.bind(this);
111
+ this.setSortItems = this.setSortItems.bind(this);
112
+ this.getVisibleColumnsKey = this.getVisibleColumnsKey.bind(this);
113
+ this.getVisibleColumns = this.getVisibleColumns.bind(this);
114
+ this.setVisibleColumns = this.setVisibleColumns.bind(this);
115
+ this.setColumns = this.setColumns.bind(this);
116
+ this.setColumns = this.setColumns.bind(this);
117
+ this.setRows = this.setRows.bind(this);
118
+ this.foreachColumn = this.foreachColumn.bind(this);
119
+ this.getColumns = this.getColumns.bind(this);
120
+ this.showModal = this.showModal.bind(this);
121
+ this.hideModal = this.hideModal.bind(this);
122
+ this.onPageChange = this.onPageChange.bind(this);
123
+ this.isSomeChecked = this.isSomeChecked.bind(this);
124
+ this.toggleAllCheckboxes = this.toggleAllCheckboxes.bind(this);
125
+ this.print = this.print.bind(this);
126
+ this.exportCSV = this.exportCSV.bind(this);
127
+ this.isAllChecked = this.isAllChecked.bind(this);
128
+ this.reload = this.reload.bind(this);
129
+ }
130
+ private getSortItemsKey(): string
131
+ {
132
+ return "ns_table_" + this.props.name + "_sort_items";
133
+ }
134
+ getSortItems(): SortItem[]
135
+ {
136
+ let storage = new IStorageLocal();
137
+ let item = storage.get(this.getSortItemsKey(), "");
138
+ try
139
+ {
140
+ return SortItem.parse(item);
141
+ } catch (error)
142
+ {
143
+ }
144
+ return [];
145
+ }
146
+ setSortItems(items: SortItem[] | null)
147
+ {
148
+ let storage = new IStorageLocal();
149
+ storage.set(this.getSortItemsKey(), SortItem.stringify(items));
150
+ this.setState({ sortItems: items }, () =>
151
+ {
152
+ this.props.onSortChanged?.(items);
153
+ this.reload(null, null);
154
+ });
155
+ }
156
+ private getVisibleColumnsKey(): string
157
+ {
158
+ return "ns_table_" + this.props.name + "_visible_columns";
159
+ }
160
+ getVisibleColumns(): { table: string, column: string }[]
161
+ {
162
+ let storage = new IStorageLocal();
163
+ let item = storage.get(this.getVisibleColumnsKey(), "");
164
+ try
165
+ {
166
+ return JSON.parse(item);
167
+ } catch (error)
168
+ {
169
+ }
170
+ return [];
171
+ }
172
+ setVisibleColumns(visible_columns: { table: string, column: string }[])
173
+ {
174
+ let storage = new IStorageLocal();
175
+ storage.set(this.getVisibleColumnsKey(), JSON.stringify(visible_columns));
176
+ this.setState({ visible_columns }, () =>
177
+ {
178
+ this.props.onVisibleColumnsChanged?.(visible_columns);
179
+ });
180
+ }
181
+ setColumns(columns: TableColumnInfo[])
182
+ {
183
+ this.setState({ columns });
184
+ }
185
+ setRows(rows: RowType[] | null, totalItems: number)
186
+ {
187
+ this.setState({ rows, totalItems }, () =>
188
+ {
189
+ this.nstable_top_div.current?.scrollIntoView({ behavior: 'smooth', block: 'center' });
190
+ });
191
+ }
192
+ foreachColumn(visible: boolean | null, handler: (column: TableColumnInfo) => void)
193
+ {
194
+ let vs = this.getVisibleColumns();
195
+ let shouldBeVisible = (c: TableColumnInfo) =>
196
+ {
197
+ if (vs.length === 0)
198
+ return true;
199
+ return vs.filter(v => v.table === c.table.name && v.column === c.name).length > 0;
200
+ };
201
+ this.state.columns.forEach(c =>
202
+ {
203
+ if (visible === null || shouldBeVisible(c) === visible)
204
+ handler(c);
205
+ })
206
+ }
207
+ getColumns(visible: boolean | null): TableColumnInfo[]
208
+ {
209
+ let columns: TableColumnInfo[] = [];
210
+ this.foreachColumn(visible, c => columns.push(c));
211
+ return columns;
212
+ }
213
+ private showModal(description: string, title?: string)
214
+ {
215
+ this.setState({ model: { show: true, description }, title });
216
+ }
217
+ private hideModal()
218
+ {
219
+ this.setState({ model: { show: false } });
220
+ }
221
+ private onPageChange(page: number, size: number)
222
+ {
223
+ this.reload(page, size);
224
+ }
225
+ public async reload(page: number | null, size: number | null)
226
+ {
227
+ this.setRows(null, 0);
228
+ if (page === null)
229
+ page = this.NSPagination.current?.getCurrentPage() ?? 0;
230
+ if (size === null)
231
+ size = this.NSPagination.current?.getPageSize() ?? 0;
232
+ try
233
+ {
234
+ let sorts = this.getSortItems();
235
+ let res = await this.props.getRows(page, size, sorts);
236
+ this.setRows(res.rows, res.count);
237
+ } catch (error)
238
+ {
239
+ }
240
+ }
241
+ private toggleAllCheckboxes()
242
+ {
243
+ let selectedIDs: string[] = [];
244
+ let selectedRows: RowType[] = [];
245
+ if (this.getSelectedIDs().length === 0)
246
+ this.state.rows?.forEach((row, rowIndex) =>
247
+ {
248
+ let id = this.props.getRowKey({ index: rowIndex, value: row });
249
+ selectedIDs.push(id);
250
+ selectedRows.push(row);
251
+ })
252
+ this.setSelectedIDs(selectedIDs, selectedRows);
253
+ }
254
+ print(rows: RowType[])
255
+ {
256
+ const printWindow = window.open('', '', 'height=500,width=800');
257
+ printWindow!.document.write(`<html><head><title>${this.props.name}</title>`);
258
+ printWindow!.document.write('<style>table { width: 100%; border-collapse: collapse; } th, td { border: 1px solid black; padding: 8px; text-align: left; }</style>');
259
+ printWindow!.document.write('</head><body>');
260
+ printWindow!.document.write('<table>');
261
+ printWindow!.document.write('<thead><tr>');
262
+
263
+ this.foreachColumn(true, column =>
264
+ {
265
+ printWindow!.document.write('<th>' + column.text + '</th>');
266
+ });
267
+
268
+ printWindow!.document.write('</tr></thead><tbody>');
269
+
270
+ // Add table rows
271
+ rows.forEach((rowValue, rowIndex) =>
272
+ {
273
+ let row = { index: rowIndex, value: rowValue };
274
+ printWindow!.document.write('<tr>');
275
+ this.foreachColumn(true, column =>
276
+ {
277
+ let cell = this.getCellTableInfo(column, row, true);
278
+ printWindow!.document.write('<td>' + (cell.formatted ?? "") + '</td>');
279
+ });
280
+ printWindow!.document.write('</tr>');
281
+ });
282
+
283
+ printWindow!.document.write('</tbody></table>');
284
+ printWindow!.document.write('</body></html>');
285
+ printWindow!.document.close();
286
+ printWindow!.print();
287
+ }
288
+ exportCSV(rows: RowType[])
289
+ {
290
+ const worksheet = utils.json_to_sheet(rows || []);
291
+ const workbook = utils.book_new();
292
+ utils.book_append_sheet(workbook, worksheet, this.props.name);
293
+ writeFile(workbook, this.props.name + ".xlsx");
294
+ }
295
+ getSelectedIDs(): string[]
296
+ {
297
+ return this.state.selectedIDs;
298
+ }
299
+ getSelectedRows(): RowType[]
300
+ {
301
+ return this.state.selectedRows;
302
+ }
303
+ setSelectedIDs(ids: string[], rows: RowType[], callback?: () => void)
304
+ {
305
+ this.setState({ selectedIDs: ids, selectedRows: rows }, () =>
306
+ {
307
+ if (this.props.onSelectedIDsChanged)
308
+ this.props.onSelectedIDsChanged();
309
+ if (callback)
310
+ callback();
311
+ });
312
+ }
313
+ private isAllChecked(): boolean
314
+ {
315
+ return this.state.rows !== null && this.state.rows.length > 0 && this.state.selectedIDs.length === this.state.rows.length;
316
+ }
317
+
318
+ private isSomeChecked(): boolean
319
+ {
320
+ return this.state.selectedIDs.length > 0 && !this.isAllChecked();
321
+ }
322
+
323
+ private getCellTableInfo(column: TableColumnInfo, row: TableRowInfo<RowType>, printable: boolean)
324
+ {
325
+ let value = (row.value as any)[column.name];
326
+ let formatted = this.getCellFormattedValue(value, column, row, printable);
327
+ return { column, row, value, formatted };
328
+ }
329
+ private getCellFormattedValue(value: any, column: TableColumnInfo, row: TableRowInfo<RowType>, printable: boolean)
330
+ {
331
+ if (this.props.getCellFormattedValue)
332
+ return this.props.getCellFormattedValue(value, column, row, printable);
333
+ return column.formatter.format(value, column, row, printable);
334
+ }
335
+ override componentDidMount(): void
336
+ {
337
+ if (!this.NSPagination.current)
338
+ this.reload(null, null);
339
+ }
340
+ override render()
341
+ {
342
+ let getRowAttributes = (row_value: RowType, row_index: number) =>
343
+ {
344
+ if (this.props.getRowAttributes)
345
+ return this.props.getRowAttributes(row_value, row_index);
346
+ return {};
347
+ }
348
+ let getColumnAttributes = (column: TableColumnInfo) =>
349
+ {
350
+ if (this.props.getColumnAttributes)
351
+ return this.props.getColumnAttributes(column);
352
+ return {};
353
+ }
354
+ let onColumnClick = (e: React.MouseEvent<HTMLTableDataCellElement, MouseEvent>, column: TableColumnInfo) =>
355
+ {
356
+ if (this.props.onColumnClick)
357
+ this.props.onColumnClick(e, column);
358
+ }
359
+ let onRowClick = (e: React.MouseEvent<HTMLTableRowElement, MouseEvent>, row: TableRowInfo<RowType>) =>
360
+ {
361
+ if (this.props.onRowClick)
362
+ this.props.onRowClick(e, row);
363
+ };
364
+ let onCellClick = (e: React.MouseEvent<HTMLTableDataCellElement, MouseEvent>, cell: TableCellInfo<RowType>) =>
365
+ {
366
+ let overided = cell.column.formatter.onclick_overrided;
367
+ if (this.props.onCellClick)
368
+ overided = this.props.onCellClick(e, cell) ?? true;
369
+ if (!overided)
370
+ this.showModal(cell.formatted, cell.column.text);
371
+ };
372
+ let content;
373
+ if (this.state.rows === null)
374
+ {
375
+ content = (
376
+ <tr className="d-flex justify-content-center align-items-center p-0">
377
+ <td className="w-100 h-100 m-0 mh-100">
378
+ <NSLoading />
379
+ </td>
380
+ </tr>
381
+ );
382
+ }
383
+ else if (this.state.rows.length === 0)
384
+ {
385
+ content = (
386
+ <tr className="d-flex justify-content-center align-items-center p-0">
387
+ <td className="w-100 h-100 m-0 mh-100">
388
+ <NSNoData lable='No Data' classList={["p-3"]} />
389
+ </td>
390
+ </tr>
391
+ );
392
+ }
393
+ else
394
+ {
395
+ content = this.state.rows.map((rowValue, rowIndex) =>
396
+ {
397
+ let row = { index: rowIndex, value: rowValue };
398
+ return <tr
399
+ key={this.props.getRowKey(row)}
400
+ {...getRowAttributes(rowValue, rowIndex)}
401
+ onClick={(e) => { onRowClick(e, row); }}
402
+ >
403
+ {
404
+ this.props.checkbox &&
405
+ <td>
406
+ <label
407
+ htmlFor={`checkbox_device_${this.props.getRowKey(row)}`}
408
+ className={Styles.ns_check_box_label}
409
+ >
410
+ <input
411
+ id={`checkbox_device_${this.props.getRowKey(row)}`}
412
+ type="checkbox"
413
+ className={Styles.ns_check_box}
414
+ checked={this.state.selectedIDs.includes(this.props.getRowKey(row))}
415
+ onChange={(e) =>
416
+ {
417
+ let selectedIDs = this.state.selectedIDs;
418
+ let selectedRows = this.state.selectedRows;
419
+ let id = this.props.getRowKey(row);
420
+ if (e.currentTarget.checked)
421
+ {
422
+ selectedIDs.push(id);
423
+ selectedRows.push(row.value);
424
+ }
425
+ else
426
+ {
427
+ selectedIDs = selectedIDs.filter(x => x !== id);
428
+ selectedRows = selectedRows.filter(x => this.props.getRowKey({ index: -1, value: x }) !== id);
429
+ }
430
+ this.setSelectedIDs(selectedIDs, selectedRows);
431
+ }}
432
+ />
433
+ </label>
434
+ </td>
435
+ }
436
+ {
437
+ this.getColumns(true).map((column, index) =>
438
+ {
439
+ column.index = index + (this.props.checkbox ? 1 : 0);
440
+ let cell = this.getCellTableInfo(column, row, false);
441
+ return (
442
+ <td className='py-3' width={column.formatter.width} {...getColumnAttributes(column)} key={column.index} data-label={`${column.text}: `} onClick={(e) =>
443
+ {
444
+ onColumnClick(e, column);
445
+ onCellClick(e, cell);
446
+ }}>
447
+
448
+ {
449
+ cell.formatted ?? ""
450
+ }
451
+ </td>
452
+ );
453
+ })
454
+ }
455
+ </tr>
456
+ });
457
+ }
458
+ let getSortSign = (column: TableColumnInfo) =>
459
+ {
460
+ if (this.state.sortItems)
461
+ {
462
+ let c = this.state.sortItems.filter(c => c.table.name === column.table.name && c.column.name === column.name)[0]
463
+ if (c)
464
+ {
465
+ if (c.ascending)
466
+ return "↑"
467
+ return "↓";
468
+ }
469
+ }
470
+ return "";
471
+ };
472
+
473
+ return (
474
+ <>
475
+ <div ref={this.nstable_top_div} />
476
+ <div
477
+ id={this.props.id}
478
+ className={this.props.classList?.join(" ") ?? ""}
479
+ style={this.props.style}
480
+ >
481
+ <table className={Styles.ns_table} >
482
+ <thead>
483
+ <tr>
484
+ {
485
+ this.props.checkbox &&
486
+ <th style={{ width: "24px", height: "24px" }}>
487
+ <label
488
+ htmlFor='checkbox'
489
+ className={Styles.ns_checkbox_label}
490
+ >
491
+ <input
492
+ id="checkbox"
493
+ type="checkbox"
494
+ className={`${Styles.ns_check_box} ${this.isSomeChecked() ? Styles.ns_indeterminate : ""}`}
495
+ checked={this.getSelectedIDs().length > 0}
496
+ onChange={this.toggleAllCheckboxes}
497
+ ></input>
498
+ </label>
499
+ </th>
500
+ }
501
+ {
502
+ this.getColumns(true).map(column => <th
503
+ key={column.name}
504
+ scope="col"
505
+ style={{ width: column.formatter.width, cursor: "pointer" }}
506
+ onClick={() =>
507
+ {
508
+ let t = new BaseMetaTable(null, column.table.name, column.table.text);
509
+ let c = new BaseMetaColumn(t, column.name, column.text, "", false);
510
+ let items = this.getSortItems();
511
+ if (!items || items.length === 0 || items[0].table.name !== t.name || items[0].column.name !== c.name)
512
+ this.setSortItems([new SortItem(t, c, true)]);
513
+ else
514
+ {
515
+ if (items[0].ascending)
516
+ this.setSortItems([new SortItem(t, c, false)]);
517
+ else
518
+ this.setSortItems(null);
519
+ }
520
+ }}
521
+ >
522
+ {
523
+ column.text + " " + getSortSign(column)
524
+ }
525
+ </th>)
526
+ }
527
+ </tr>
528
+ </thead>
529
+ <tbody className={Styles.ns_tbody}>
530
+ {content}
531
+ </tbody>
532
+ </table>
533
+ <NSSpace size={NSSpaceSizeType.MINI} />
534
+ <section className={Styles.ns_table_footer}>
535
+ {
536
+ (this.props.ui?.pagination ?? true) &&
537
+ <NSPagination ref={this.NSPagination} totalItems={this.state.totalItems} onPageChange={this.onPageChange} />
538
+ }
539
+ <NSSpace size={NSSpaceSizeType.MINI} classList={["d-lg-none"]} />
540
+ <div className={Styles.ns_button_panel}>
541
+ {
542
+ this.state.pageSelectionMode !== PageSelectionMode.Hidden &&
543
+ <NSDialogPageSelection<RowType>
544
+ icon={
545
+ this.state.pageSelectionMode === PageSelectionMode.Print ? "https://static.namirasoft.com/image/concept/print/blue.svg" :
546
+ this.state.pageSelectionMode === PageSelectionMode.CSV ? "https://static.namirasoft.com/image/concept/export/blue.svg" : ""
547
+ }
548
+ current_page={this.NSPagination.current?.getCurrentPage() ?? 1}
549
+ current_size={this.NSPagination.current?.getPageSize() ?? 0}
550
+ max_page={1}
551
+ getItems={async (page, size, selected) =>
552
+ {
553
+ if (selected)
554
+ {
555
+ let rows: RowType[] = [];
556
+ if (this.state.rows)
557
+ for (let i = 0; i < this.state.rows.length; i++)
558
+ {
559
+ const row = { index: i, value: this.state.rows[i] };
560
+ let id = this.props.getRowKey(row);
561
+ if (this.state.selectedIDs.includes(id))
562
+ rows.push(row.value);
563
+ }
564
+ return rows;
565
+ }
566
+ let res = await this.props.getRows(page, size, this.getSortItems());
567
+ return res.rows;
568
+ }}
569
+ onFinish={async (items: RowType[]) =>
570
+ {
571
+ if (this.state.pageSelectionMode === PageSelectionMode.Print)
572
+ this.print(items);
573
+ else if (this.state.pageSelectionMode === PageSelectionMode.CSV)
574
+ this.exportCSV(items);
575
+ }}
576
+ onClose={() => { this.setState({ pageSelectionMode: PageSelectionMode.Hidden }); }
577
+ }
578
+ />
579
+ }
580
+ <NSButton
581
+ title='Chart'
582
+ icon={{ src: "https://static.namirasoft.com/image/concept/chart/blue.svg" }}
583
+ onClick={{
584
+ action: () =>
585
+ {
586
+ this.showModal(" ", "This feature will be available soon in upcoming versions.");
587
+ },
588
+ showLoading: false
589
+ }}
590
+ style={{ border: '1px solid rgba(255, 148, 50, 1)', width: "128px" }}
591
+ />
592
+ <NSButton
593
+ title='Print'
594
+ icon={{ src: "https://static.namirasoft.com/image/concept/print/blue.svg" }}
595
+ onClick={{
596
+ action: () => { this.setState({ pageSelectionMode: PageSelectionMode.Print }); },
597
+ showLoading: false
598
+ }}
599
+ style={{ border: '1px solid rgba(255, 148, 50, 1)', width: "128px" }}
600
+ />
601
+ <NSButton
602
+ title='Export'
603
+ icon={{ src: "https://static.namirasoft.com/image/concept/export/blue.svg" }}
604
+ onClick={{
605
+ action: () => { this.setState({ pageSelectionMode: PageSelectionMode.CSV }); },
606
+ showLoading: false
607
+ }}
608
+ style={{ border: '1px solid rgba(255, 148, 50, 1)', width: "128px" }}
609
+ />
610
+ <NSButton
611
+ title='Refresh'
612
+ icon={{ src: "https://static.namirasoft.com/image/concept/refresh/blue.svg" }}
613
+ onClick={{
614
+ action: async (onFinished) =>
615
+ {
616
+ this.reload(null, null).then(onFinished).catch(onFinished);
617
+ }
618
+ }}
619
+ style={{ border: '1px solid rgba(3, 119, 255, 1)', width: "128px" }} />
620
+ </div>
621
+ </section>
622
+ {
623
+ this.state.model.show &&
624
+ <NSDialogInfo
625
+ description={this.state.model.description}
626
+ onClose={() => { this.hideModal(); }}
627
+ title={this.state.title}
628
+ show_as_code={true}
629
+ >
630
+ <></>
631
+ </NSDialogInfo>
632
+ }
633
+ </div >
634
+ </>
635
+ );
636
+ }
637
637
  }