slick-table 1.2.1 → 1.2.3

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 (135) hide show
  1. package/dist/index.cjs.js +116 -114
  2. package/dist/index.es.js +26935 -24772
  3. package/dist/styles/icons.scss +4 -0
  4. package/dist/types/entities/drawer-run-query/index.d.ts +2 -0
  5. package/dist/types/entities/drawer-run-query/index.d.ts.map +1 -0
  6. package/dist/types/entities/drawer-run-query/lib/grouping/getGroupLabel.d.ts +8 -0
  7. package/dist/types/entities/drawer-run-query/lib/grouping/getGroupLabel.d.ts.map +1 -0
  8. package/dist/types/entities/drawer-run-query/lib/grouping/groupQueriesByDate.d.ts +4 -0
  9. package/dist/types/entities/drawer-run-query/lib/grouping/groupQueriesByDate.d.ts.map +1 -0
  10. package/dist/types/entities/drawer-run-query/lib/grouping/index.d.ts +2 -0
  11. package/dist/types/entities/drawer-run-query/lib/grouping/index.d.ts.map +1 -0
  12. package/dist/types/entities/drawer-run-query/lib/hooks/index.d.ts +3 -0
  13. package/dist/types/entities/drawer-run-query/lib/hooks/index.d.ts.map +1 -0
  14. package/dist/types/entities/drawer-run-query/lib/hooks/useResizeCanvas.d.ts +2 -0
  15. package/dist/types/entities/drawer-run-query/lib/hooks/useResizeCanvas.d.ts.map +1 -0
  16. package/dist/types/entities/drawer-run-query/lib/hooks/useSubscribeToEvent.d.ts +3 -0
  17. package/dist/types/entities/drawer-run-query/lib/hooks/useSubscribeToEvent.d.ts.map +1 -0
  18. package/dist/types/entities/drawer-run-query/lib/index.d.ts +4 -0
  19. package/dist/types/entities/drawer-run-query/lib/index.d.ts.map +1 -0
  20. package/dist/types/entities/drawer-run-query/lib/table/getColumsHash.d.ts +3 -0
  21. package/dist/types/entities/drawer-run-query/lib/table/getColumsHash.d.ts.map +1 -0
  22. package/dist/types/entities/drawer-run-query/lib/table/index.d.ts +3 -0
  23. package/dist/types/entities/drawer-run-query/lib/table/index.d.ts.map +1 -0
  24. package/dist/types/entities/drawer-run-query/lib/table/tableQuery.d.ts +3 -0
  25. package/dist/types/entities/drawer-run-query/lib/table/tableQuery.d.ts.map +1 -0
  26. package/dist/types/entities/drawer-run-query/model/consts/consts.d.ts +3 -0
  27. package/dist/types/entities/drawer-run-query/model/consts/consts.d.ts.map +1 -0
  28. package/dist/types/entities/drawer-run-query/model/consts/index.d.ts +2 -0
  29. package/dist/types/entities/drawer-run-query/model/consts/index.d.ts.map +1 -0
  30. package/dist/types/entities/drawer-run-query/model/index.d.ts +3 -0
  31. package/dist/types/entities/drawer-run-query/model/index.d.ts.map +1 -0
  32. package/dist/types/entities/drawer-run-query/model/types/IQueryGroup.d.ts +6 -0
  33. package/dist/types/entities/drawer-run-query/model/types/IQueryGroup.d.ts.map +1 -0
  34. package/dist/types/entities/drawer-run-query/model/types/index.d.ts +2 -0
  35. package/dist/types/entities/drawer-run-query/model/types/index.d.ts.map +1 -0
  36. package/dist/types/entities/drawer-run-query/ui/DrawerRunQuery.d.ts +7 -0
  37. package/dist/types/entities/drawer-run-query/ui/DrawerRunQuery.d.ts.map +1 -0
  38. package/dist/types/entities/drawer-run-query/ui/DrawerRunQuery.style.d.ts +37 -0
  39. package/dist/types/entities/drawer-run-query/ui/DrawerRunQuery.style.d.ts.map +1 -0
  40. package/dist/types/entities/drawer-run-query/ui/QueryHistory/QueryHistory.d.ts +9 -0
  41. package/dist/types/entities/drawer-run-query/ui/QueryHistory/QueryHistory.d.ts.map +1 -0
  42. package/dist/types/entities/drawer-run-query/ui/QueryHistory/QueryHistory.style.d.ts +23 -0
  43. package/dist/types/entities/drawer-run-query/ui/QueryHistory/QueryHistory.style.d.ts.map +1 -0
  44. package/dist/types/entities/drawer-run-query/ui/QueryHistory/index.d.ts +2 -0
  45. package/dist/types/entities/drawer-run-query/ui/QueryHistory/index.d.ts.map +1 -0
  46. package/dist/types/entities/drawer-run-query/ui/index.d.ts +2 -0
  47. package/dist/types/entities/drawer-run-query/ui/index.d.ts.map +1 -0
  48. package/dist/types/entities/popup-summary/ui/PopupSummary.style.d.ts +1 -1
  49. package/dist/types/features/column-filters/ui/ButtonReset/ButtonReset.style.d.ts +1 -1
  50. package/dist/types/features/context-menu/ui/ButtonQuery/index.d.ts +2 -0
  51. package/dist/types/features/context-menu/ui/ButtonQuery/index.d.ts.map +1 -0
  52. package/dist/types/features/context-menu/ui/ButtonQuery/ui/ButtonQuery.d.ts +7 -0
  53. package/dist/types/features/context-menu/ui/ButtonQuery/ui/ButtonQuery.d.ts.map +1 -0
  54. package/dist/types/features/context-menu/ui/ButtonQuery/ui/index.d.ts +2 -0
  55. package/dist/types/features/context-menu/ui/ButtonQuery/ui/index.d.ts.map +1 -0
  56. package/dist/types/features/context-menu/ui/ContextMenu.d.ts.map +1 -1
  57. package/dist/types/features/header-context-menu/lib/visibility/getHidableColumnIds.d.ts.map +1 -1
  58. package/dist/types/features/header-context-menu/ui/Item/Item.style.d.ts +1 -1
  59. package/dist/types/shared/lib/dom/doNotForwardProps.d.ts +2 -0
  60. package/dist/types/shared/lib/dom/doNotForwardProps.d.ts.map +1 -0
  61. package/dist/types/shared/lib/dom/index.d.ts +1 -0
  62. package/dist/types/shared/lib/dom/index.d.ts.map +1 -1
  63. package/dist/types/shared/lib/localStrore/model/classes/Queries.d.ts +7 -0
  64. package/dist/types/shared/lib/localStrore/model/classes/Queries.d.ts.map +1 -0
  65. package/dist/types/shared/lib/localStrore/model/classes/index.d.ts +1 -0
  66. package/dist/types/shared/lib/localStrore/model/classes/index.d.ts.map +1 -1
  67. package/dist/types/shared/lib/localStrore/model/enums/EStorageKey.d.ts +2 -1
  68. package/dist/types/shared/lib/localStrore/model/enums/EStorageKey.d.ts.map +1 -1
  69. package/dist/types/shared/lib/localStrore/model/localStore.d.ts +2 -1
  70. package/dist/types/shared/lib/localStrore/model/localStore.d.ts.map +1 -1
  71. package/dist/types/shared/lib/slickgrid/index.d.ts +1 -1
  72. package/dist/types/shared/lib/slickgrid/index.d.ts.map +1 -1
  73. package/dist/types/shared/lib/slickgrid/model/events/eventRunQuery.d.ts +13 -0
  74. package/dist/types/shared/lib/slickgrid/model/events/eventRunQuery.d.ts.map +1 -0
  75. package/dist/types/shared/lib/slickgrid/model/events/index.d.ts +1 -0
  76. package/dist/types/shared/lib/slickgrid/model/events/index.d.ts.map +1 -1
  77. package/dist/types/shared/lib/slickgrid/model/index.d.ts +1 -1
  78. package/dist/types/shared/lib/slickgrid/model/index.d.ts.map +1 -1
  79. package/dist/types/shared/lib/slickgrid/ui/SlickgridTable/ui/SlickgridTable.d.ts.map +1 -1
  80. package/dist/types/shared/lib/slickgrid/ui/columns/columnIsEdited/ui/columnIsEdited.d.ts.map +1 -1
  81. package/dist/types/shared/model/consts/columnId.d.ts +1 -0
  82. package/dist/types/shared/model/consts/columnId.d.ts.map +1 -1
  83. package/dist/types/shared/model/consts/index.d.ts +1 -1
  84. package/dist/types/shared/model/consts/index.d.ts.map +1 -1
  85. package/dist/types/shared/model/types/IRecentQuery.d.ts +5 -0
  86. package/dist/types/shared/model/types/IRecentQuery.d.ts.map +1 -0
  87. package/dist/types/shared/model/types/index.d.ts +1 -0
  88. package/dist/types/shared/model/types/index.d.ts.map +1 -1
  89. package/package.json +2 -1
  90. package/src/app/styles/icons.scss +4 -0
  91. package/src/entities/drawer-run-query/index.ts +1 -0
  92. package/src/entities/drawer-run-query/lib/grouping/getGroupLabel.spec.ts +46 -0
  93. package/src/entities/drawer-run-query/lib/grouping/getGroupLabel.ts +26 -0
  94. package/src/entities/drawer-run-query/lib/grouping/groupQueriesByDate.spec.ts +54 -0
  95. package/src/entities/drawer-run-query/lib/grouping/groupQueriesByDate.ts +37 -0
  96. package/src/entities/drawer-run-query/lib/grouping/index.ts +1 -0
  97. package/src/entities/drawer-run-query/lib/hooks/index.ts +2 -0
  98. package/src/entities/drawer-run-query/lib/hooks/useResizeCanvas.ts +13 -0
  99. package/src/entities/drawer-run-query/lib/hooks/useSubscribeToEvent.ts +20 -0
  100. package/src/entities/drawer-run-query/lib/index.ts +3 -0
  101. package/src/entities/drawer-run-query/lib/table/getColumsHash.ts +18 -0
  102. package/src/entities/drawer-run-query/lib/table/index.ts +2 -0
  103. package/src/entities/drawer-run-query/lib/table/tableQuery.ts +3 -0
  104. package/src/entities/drawer-run-query/model/consts/consts.ts +2 -0
  105. package/src/entities/drawer-run-query/model/consts/index.ts +1 -0
  106. package/src/entities/drawer-run-query/model/index.ts +2 -0
  107. package/src/entities/drawer-run-query/model/types/IQueryGroup.ts +6 -0
  108. package/src/entities/drawer-run-query/model/types/index.ts +1 -0
  109. package/src/entities/drawer-run-query/ui/DrawerRunQuery.style.ts +129 -0
  110. package/src/entities/drawer-run-query/ui/DrawerRunQuery.tsx +195 -0
  111. package/src/entities/drawer-run-query/ui/QueryHistory/QueryHistory.style.ts +53 -0
  112. package/src/entities/drawer-run-query/ui/QueryHistory/QueryHistory.tsx +62 -0
  113. package/src/entities/drawer-run-query/ui/QueryHistory/index.ts +1 -0
  114. package/src/entities/drawer-run-query/ui/index.ts +1 -0
  115. package/src/features/context-menu/ui/ButtonQuery/index.ts +1 -0
  116. package/src/features/context-menu/ui/ButtonQuery/ui/ButtonQuery.tsx +26 -0
  117. package/src/features/context-menu/ui/ButtonQuery/ui/index.ts +1 -0
  118. package/src/features/context-menu/ui/ContextMenu.tsx +2 -0
  119. package/src/features/header-context-menu/lib/visibility/getHidableColumnIds.ts +2 -1
  120. package/src/shared/lib/dom/doNotForwardProps.ts +5 -0
  121. package/src/shared/lib/dom/index.ts +1 -0
  122. package/src/shared/lib/localStrore/model/classes/Queries.ts +40 -0
  123. package/src/shared/lib/localStrore/model/classes/index.ts +1 -0
  124. package/src/shared/lib/localStrore/model/enums/EStorageKey.ts +1 -0
  125. package/src/shared/lib/localStrore/model/localStore.ts +8 -1
  126. package/src/shared/lib/slickgrid/index.ts +1 -0
  127. package/src/shared/lib/slickgrid/model/events/eventRunQuery.ts +24 -0
  128. package/src/shared/lib/slickgrid/model/events/index.ts +1 -0
  129. package/src/shared/lib/slickgrid/model/index.ts +1 -0
  130. package/src/shared/lib/slickgrid/ui/SlickgridTable/ui/SlickgridTable.tsx +2 -0
  131. package/src/shared/lib/slickgrid/ui/columns/columnIsEdited/ui/columnIsEdited.ts +3 -2
  132. package/src/shared/model/consts/columnId.ts +1 -0
  133. package/src/shared/model/consts/index.ts +1 -1
  134. package/src/shared/model/types/IRecentQuery.ts +4 -0
  135. package/src/shared/model/types/index.ts +1 -0
@@ -0,0 +1,5 @@
1
+ export interface IRecentQuery {
2
+ time: string;
3
+ query: string;
4
+ }
5
+ //# sourceMappingURL=IRecentQuery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IRecentQuery.d.ts","sourceRoot":"","sources":["../../../../../src/shared/model/types/IRecentQuery.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd"}
@@ -12,6 +12,7 @@ export type { IHotKeysBehavior } from './IHotKeysBehavior';
12
12
  export type { IHtmlDocElements } from './IHtmlDocElements';
13
13
  export type { IObserver } from './IObserver';
14
14
  export type { IPrinter } from './IPrinter';
15
+ export type { IRecentQuery } from './IRecentQuery';
15
16
  export type { ISlickTable } from './ISlickTable';
16
17
  export type { ISlickRow } from './ISlickRow';
17
18
  export type { ITotalCalculator } from './ITotalCalculator';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/shared/model/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,YAAY,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,YAAY,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACzE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/shared/model/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,YAAY,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,YAAY,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACzE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slick-table",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "Enhanced version of SlickGrid library",
5
5
  "private": false,
6
6
  "type": "module",
@@ -48,6 +48,7 @@
48
48
  "@mui/material": "^6.1.6",
49
49
  "@mui/x-date-pickers": "^7.22.2",
50
50
  "moment": "^2.30.1",
51
+ "myworkql": "^0.1.0",
51
52
  "pikaday": "^1.8.2",
52
53
  "react": "^18.3.1",
53
54
  "react-dom": "^18.3.1",
@@ -15,3 +15,7 @@ $red: #ff3737;
15
15
  @include svg("sgi-link-off", $gray, "M17,7H13V8.9H17C18.71,8.9 20.1,10.29 20.1,12C20.1,13.43 19.12,14.63 17.79,15L19.25,16.44C20.88,15.61 22,13.95 22,12A5,5 0 0,0 17,7M16,11H13.81L15.81,13H16V11M2,4.27L5.11,7.38C3.29,8.12 2,9.91 2,12A5,5 0 0,0 7,17H11V15.1H7C5.29,15.1 3.9,13.71 3.9,12C3.9,10.41 5.11,9.1 6.66,8.93L8.73,11H8V13H10.73L13,15.27V17H14.73L18.74,21L20,19.74L3.27,3L2,4.27Z");
16
16
  @include svg("sgi-notification-clear-all", $gray, "M5,13H19V11H5M3,17H17V15H3M7,7V9H21V7");
17
17
  @include svg("sgi-printer", $gray, "M18,3H6V7H18M19,12A1,1 0 0,1 18,11A1,1 0 0,1 19,10A1,1 0 0,1 20,11A1,1 0 0,1 19,12M16,19H8V14H16M19,8H5A3,3 0 0,0 2,11V17H6V21H18V17H22V11A3,3 0 0,0 19,8Z");
18
+ @include svg("sgi-table-large", $gray, "M4,3H20A2,2 0 0,1 22,5V20A2,2 0 0,1 20,22H4A2,2 0 0,1 2,20V5A2,2 0 0,1 4,3M4,7V10H8V7H4M10,7V10H14V7H10M20,10V7H16V10H20M4,12V15H8V12H4M4,20H8V17H4V20M10,12V15H14V12H10M10,20H14V17H10V20M20,20V17H16V20H20M20,12H16V15H20V12Z");
19
+ @include svg("sgi-minus", $gray, "M19,13H5V11H19V13Z");
20
+ @include svg("sgi-close", $gray, "M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z");
21
+ @include svg("sgi-arrow-expand", $gray, "M10,21V19H6.41L10.91,14.5L9.5,13.09L5,17.59V14H3V21H10M14.5,10.91L19,6.41V10H21V3H14V5H17.59L13.09,9.5L14.5,10.91Z");
@@ -0,0 +1 @@
1
+ export { DrawerRunQuery } from "./ui";
@@ -0,0 +1,46 @@
1
+ import moment from "moment";
2
+
3
+ import { getGroupLabel } from "./getGroupLabel";
4
+
5
+ const toDateString = (date: Date): string => moment(date).format("YYYY-MM-DD");
6
+
7
+ const daysAgo = (days: number): Date => moment().subtract(days, "day").toDate();
8
+
9
+ describe("pages | chat-with-ai | lib | getGroupLabel", () => {
10
+ it('returns "Today" for the current date', () => {
11
+ expect(getGroupLabel(new Date())).toBe("Today");
12
+ });
13
+
14
+ it('returns "Yesterday" for the previous calendar day', () => {
15
+ expect(getGroupLabel(daysAgo(1))).toBe("Yesterday");
16
+ });
17
+
18
+ it("returns a relative label for dates within the relative limit", () => {
19
+ expect(getGroupLabel(daysAgo(2))).toBe("2 days");
20
+ expect(getGroupLabel(daysAgo(15))).toBe("15 days");
21
+ });
22
+
23
+ it('returns "30 days" on the last day of the relative limit', () => {
24
+ expect(getGroupLabel(daysAgo(30))).toBe("30 days");
25
+ });
26
+
27
+ it("returns the formatted date for dates beyond the relative limit", () => {
28
+ const lastMonth = daysAgo(31);
29
+ const lastYear = daysAgo(365);
30
+
31
+ expect(getGroupLabel(lastMonth)).toBe(toDateString(lastMonth));
32
+ expect(getGroupLabel(lastYear)).toBe(toDateString(lastYear));
33
+ expect(getGroupLabel(lastMonth)).toMatch(/^\d{4}-\d{2}-\d{2}$/);
34
+ });
35
+
36
+ it("uses calendar days and ignores the time of day", () => {
37
+ const yesterdayEvening = daysAgo(1);
38
+ yesterdayEvening.setHours(23, 59, 59, 999);
39
+
40
+ const thirtyDaysAgoEvening = daysAgo(30);
41
+ thirtyDaysAgoEvening.setHours(23, 59, 59, 999);
42
+
43
+ expect(getGroupLabel(yesterdayEvening)).toBe("Yesterday");
44
+ expect(getGroupLabel(thirtyDaysAgoEvening)).toBe("30 days");
45
+ });
46
+ });
@@ -0,0 +1,26 @@
1
+ import moment from "moment";
2
+
3
+ import { EDateFormat } from "shared/model/enums";
4
+
5
+ const RELATIVE_DAY_LIMIT = 30;
6
+
7
+ /**
8
+ * Builds a human readable label for the day a query was run on.
9
+ * The label is relative ("Today", "Yesterday", "N days") within the limit
10
+ * and an absolute date after it. Days are calendar days, the time of day
11
+ * is ignored.
12
+ * */
13
+ export const getGroupLabel = (date: Date): string => {
14
+ const value = moment(date);
15
+
16
+ if (value.isSame(moment(), "day")) return "Today";
17
+ if (value.isSame(moment().subtract(1, "day"), "day")) return "Yesterday";
18
+
19
+ const daysAgo = moment()
20
+ .startOf("day")
21
+ .diff(value.clone().startOf("day"), "days");
22
+
23
+ if (daysAgo <= RELATIVE_DAY_LIMIT) return `${daysAgo} days`;
24
+
25
+ return value.format(EDateFormat.db);
26
+ };
@@ -0,0 +1,54 @@
1
+ import moment from "moment";
2
+
3
+ import { IRecentQuery } from "shared/model/types";
4
+
5
+ import { groupQueriesByDate } from "./groupQueriesByDate";
6
+
7
+ const toTime = (daysAgo: number, time = "12:00:00"): string =>
8
+ moment().subtract(daysAgo, "day").format(`YYYY-MM-DD ${time}`);
9
+
10
+ const makeQuery = (query: string, time: string): IRecentQuery => ({
11
+ query,
12
+ time,
13
+ });
14
+
15
+ describe("pages | chat-with-ai | lib | groupConversationsByDate", () => {
16
+ it("groups conversations into today, yesterday, N days and dated buckets", () => {
17
+ const conversations = [
18
+ makeQuery("older", toTime(31)),
19
+ makeQuery("30d", toTime(30)),
20
+ makeQuery("2d", toTime(2)),
21
+ makeQuery("yesterday", toTime(1)),
22
+ makeQuery("today-late", toTime(0, "15:00:00")),
23
+ makeQuery("today-early", toTime(0, "09:00:00")),
24
+ ];
25
+
26
+ const groups = groupQueriesByDate(conversations);
27
+
28
+ expect(groups.map((group) => group.label)).toEqual([
29
+ "Today",
30
+ "Yesterday",
31
+ "2 days",
32
+ "30 days",
33
+ toTime(31).slice(0, 10),
34
+ ]);
35
+ });
36
+
37
+ it("sorts conversations within a group by time descending", () => {
38
+ const conversations = [
39
+ makeQuery("early", toTime(0, "09:00:00")),
40
+ makeQuery("late", toTime(0, "15:00:00")),
41
+ ];
42
+
43
+ const groups = groupQueriesByDate(conversations);
44
+
45
+ expect(groups[0].queries.map(({ query }) => query)).toEqual([
46
+ "late",
47
+ "early",
48
+ ]);
49
+ });
50
+
51
+ it("returns an empty array for empty input", () => {
52
+ expect(groupQueriesByDate([])).toEqual([]);
53
+ });
54
+ });
@@ -0,0 +1,37 @@
1
+ import moment from "moment";
2
+
3
+ import { dateFormats } from "shared/model/consts";
4
+ import { EDateFormat } from "shared/model/enums";
5
+ import { IRecentQuery } from "shared/model/types";
6
+
7
+ import { IQueryGroup } from "../../model";
8
+ import { getGroupLabel } from "./getGroupLabel";
9
+
10
+ export const groupQueriesByDate = (
11
+ recentQueries: IRecentQuery[],
12
+ ): IQueryGroup[] => {
13
+ const sorted = [...recentQueries].sort(
14
+ (a, b) =>
15
+ moment(b.time, dateFormats).valueOf() -
16
+ moment(a.time, dateFormats).valueOf(),
17
+ );
18
+
19
+ const groups = new Map<string, IQueryGroup>();
20
+
21
+ for (const query of sorted) {
22
+ const date = moment(query.time, dateFormats).startOf("day");
23
+ const key = date.format(EDateFormat.db);
24
+
25
+ const group = groups.get(key);
26
+ if (group) {
27
+ group.queries.push(query);
28
+ } else {
29
+ groups.set(key, {
30
+ label: getGroupLabel(date.toDate()),
31
+ queries: [query],
32
+ });
33
+ }
34
+ }
35
+
36
+ return Array.from(groups.values());
37
+ };
@@ -0,0 +1 @@
1
+ export { groupQueriesByDate } from "./groupQueriesByDate";
@@ -0,0 +1,2 @@
1
+ export { useResizeCanvas } from "./useResizeCanvas";
2
+ export { useSubscribeToEvent } from "./useSubscribeToEvent";
@@ -0,0 +1,13 @@
1
+ import { useEffect } from "react";
2
+
3
+ import { TRANSITION_MS } from "../../model";
4
+ import { tableQuery } from "../table";
5
+
6
+ export function useResizeCanvas(isExpanded: boolean) {
7
+ useEffect(() => {
8
+ if (!isExpanded) return;
9
+ setTimeout(() => {
10
+ tableQuery.grid?.resizeCanvas();
11
+ }, TRANSITION_MS);
12
+ }, [isExpanded]);
13
+ }
@@ -0,0 +1,20 @@
1
+ import { Dispatch, SetStateAction, useEffect } from "react";
2
+
3
+ import { eventRunQuery } from "shared/lib/slickgrid";
4
+
5
+ export function useSubscribeToEvent(
6
+ setIsOpened: Dispatch<SetStateAction<boolean>>,
7
+ tableId: string,
8
+ ) {
9
+ useEffect(() => {
10
+ function callback() {
11
+ const { open, table } = eventRunQuery;
12
+ if (table?.id !== tableId) return;
13
+ setIsOpened(open);
14
+ }
15
+ eventRunQuery.subscribe(callback);
16
+ return () => {
17
+ eventRunQuery.unsubscribe(callback);
18
+ };
19
+ }, [tableId]);
20
+ }
@@ -0,0 +1,3 @@
1
+ export { groupQueriesByDate } from "./grouping";
2
+ export { useResizeCanvas, useSubscribeToEvent } from "./hooks";
3
+ export { tableQuery, getColumsHash } from "./table";
@@ -0,0 +1,18 @@
1
+ import { eventRunQuery } from "shared/lib/slickgrid";
2
+ import { IS_EDITED } from "shared/model/consts";
3
+ import { IColumn } from "shared/model/types";
4
+
5
+ export function getColumsHash(): Record<string, IColumn> {
6
+ const table = eventRunQuery.table;
7
+ if (!table) return {};
8
+ const grid = table.grid;
9
+ if (!grid) return {};
10
+ const columns: IColumn[] = grid.getColumns();
11
+ const result: Record<string, IColumn> = {};
12
+ for (const column of columns) {
13
+ if (column.id !== "_checkbox_selector" && column.id !== IS_EDITED) {
14
+ result[column.id] = column;
15
+ }
16
+ }
17
+ return result;
18
+ }
@@ -0,0 +1,2 @@
1
+ export { tableQuery } from "./tableQuery";
2
+ export { getColumsHash } from "./getColumsHash";
@@ -0,0 +1,3 @@
1
+ import { SlickTable } from "shared/lib/slickgrid/model/SlickTable/table/SlickTable";
2
+
3
+ export const tableQuery = new SlickTable({ id: "table-query" });
@@ -0,0 +1,2 @@
1
+ export const TRANSITION_MS = 300;
2
+ export const QUERY_LANGUAGE = "QUERY_LANGUAGE";
@@ -0,0 +1 @@
1
+ export { QUERY_LANGUAGE, TRANSITION_MS } from "./consts";
@@ -0,0 +1,2 @@
1
+ export { QUERY_LANGUAGE, TRANSITION_MS } from "./consts";
2
+ export type { IQueryGroup } from "./types";
@@ -0,0 +1,6 @@
1
+ import { IRecentQuery } from "shared/model/types";
2
+
3
+ export interface IQueryGroup {
4
+ label: string;
5
+ queries: IRecentQuery[];
6
+ }
@@ -0,0 +1 @@
1
+ export type { IQueryGroup } from "./IQueryGroup";
@@ -0,0 +1,129 @@
1
+ import {
2
+ Box,
3
+ Button,
4
+ Drawer,
5
+ IconButton,
6
+ InputAdornment,
7
+ TextField,
8
+ Typography,
9
+ styled,
10
+ } from "@mui/material";
11
+
12
+ import { doNotForwardProps } from "shared/lib/dom";
13
+
14
+ import { TRANSITION_MS } from "../model";
15
+
16
+ const HEIGHT_EXPANDED = "90vh";
17
+ const HEIGHT_COLLAPSED_EM = 11;
18
+
19
+ const StyledDrawer = styled(Drawer, {
20
+ shouldForwardProp: doNotForwardProps(["isExpanded"]),
21
+ })<{ isExpanded: boolean }>(({ isExpanded }) => ({
22
+ zIndex: 1300,
23
+ "& .MuiDrawer-paper": {
24
+ borderTopLeftRadius: "10px",
25
+ borderTopRightRadius: "10px",
26
+ columnGap: "1em",
27
+ display: "grid",
28
+ gridTemplateColumns: "25% 1fr",
29
+ transition: `${TRANSITION_MS / 1000}s`,
30
+ height: isExpanded ? HEIGHT_EXPANDED : `${HEIGHT_COLLAPSED_EM}em`,
31
+ padding: "1em",
32
+ },
33
+ "& div.MuiBackdrop-root": {
34
+ opacity: "0 !important",
35
+ },
36
+ }));
37
+
38
+ const Header = styled(Box)({
39
+ display: "flex",
40
+ justifyContent: "space-between",
41
+ });
42
+
43
+ const Title = styled(Typography)({
44
+ color: "#235B95",
45
+ marginBottom: "0.5em",
46
+ fontWeight: "600",
47
+ fontSize: "16px",
48
+ letterSpacing: "-2%",
49
+ minWidth: "14em",
50
+ });
51
+
52
+ const RowsNumber = styled(Box)({
53
+ color: "#1E456F",
54
+ });
55
+
56
+ const StyledTextField = styled(TextField)({
57
+ width: "100%",
58
+ "& .MuiInputBase-root": {
59
+ borderRadius: "10px",
60
+ padding: "11px 14px",
61
+ color: "#235B95",
62
+ },
63
+ });
64
+
65
+ const EndAdornment = styled(InputAdornment)({
66
+ alignSelf: "flex-start",
67
+ marginTop: "-2px",
68
+ });
69
+
70
+ const ClearButton = styled(IconButton)({
71
+ color: "#808080",
72
+ padding: "4px",
73
+ "& .sgi": {
74
+ display: "block",
75
+ },
76
+ "&:hover": {
77
+ backgroundColor: "#E8F4FE",
78
+ color: "#235B95",
79
+ },
80
+ });
81
+
82
+ const ContainerInput = styled(Box)({
83
+ display: "flex",
84
+ columnGap: "0.5em",
85
+ marginTop: "1em",
86
+ width: "100%",
87
+ marginBottom: "1em",
88
+ });
89
+
90
+ const ColumnName = styled("span")({
91
+ fontSize: "0.875rem",
92
+ cursor: "pointer",
93
+ backgroundColor: "aliceblue",
94
+ borderRadius: "10px",
95
+ padding: "5px",
96
+ });
97
+
98
+ const ContainerTable = styled(Box, {
99
+ shouldForwardProp: doNotForwardProps(["isExpanded"]),
100
+ })<{ isExpanded: boolean }>(({ isExpanded }) => ({
101
+ overflowY: "auto",
102
+ transition: `${TRANSITION_MS / 1000}s`,
103
+ height: isExpanded
104
+ ? `calc(${HEIGHT_EXPANDED} - ${HEIGHT_COLLAPSED_EM + 2}em)`
105
+ : "0vh",
106
+ }));
107
+
108
+ const StyledButton = styled(Button)({
109
+ backgroundColor: "#2FAF7D",
110
+ color: "#FBFBFB",
111
+ textTransform: "none",
112
+ width: "229px",
113
+ height: "45px",
114
+ borderRadius: "10px",
115
+ });
116
+
117
+ export default {
118
+ Button: StyledButton,
119
+ ClearButton,
120
+ ColumnName,
121
+ ContainerInput,
122
+ ContainerTable,
123
+ Drawer: StyledDrawer,
124
+ EndAdornment,
125
+ Header,
126
+ RowsNumber,
127
+ TextField: StyledTextField,
128
+ Title,
129
+ };
@@ -0,0 +1,195 @@
1
+ import { Box, IconButton, Tooltip } from "@mui/material";
2
+ import { GvizTable } from "myworkql";
3
+ import { ChangeEvent, FC, MouseEvent, useRef, useState } from "react";
4
+ import { SlickDataView } from "slickgrid";
5
+
6
+ import { localStore } from "shared/lib/localStrore";
7
+ import { SlickgridTable, eventRunQuery } from "shared/lib/slickgrid";
8
+ import { IColumn } from "shared/model/types";
9
+
10
+ import {
11
+ getColumsHash,
12
+ tableQuery,
13
+ useResizeCanvas,
14
+ useSubscribeToEvent,
15
+ } from "../lib";
16
+ import { QueryHistory } from "./QueryHistory";
17
+
18
+ import Styled from "./DrawerRunQuery.style";
19
+
20
+ export const DrawerRunQuery: FC<Props> = ({ tableId }) => {
21
+ const [query, setQuery] = useState("");
22
+ const [isOpened, setIsOpened] = useState(false);
23
+ const [isExpanded, setIsExpanded] = useState(false);
24
+ const [items, setItems] = useState<Record<string, any>[]>([]);
25
+ const [columns, setColumns] = useState<IColumn[]>([]);
26
+ const queryInputRef = useRef<HTMLTextAreaElement>(null);
27
+ const columnsHash = getColumsHash();
28
+
29
+ function closeDrawer() {
30
+ eventRunQuery.open = false;
31
+ }
32
+
33
+ function updateQuery(event: ChangeEvent<HTMLTextAreaElement>) {
34
+ setQuery(event.target.value);
35
+ }
36
+
37
+ function clearQuery() {
38
+ const input = queryInputRef.current;
39
+ setQuery("");
40
+ requestAnimationFrame(() => input?.focus());
41
+ }
42
+
43
+ function pasteColumnId(event: MouseEvent<HTMLSpanElement>) {
44
+ const columnId = event.currentTarget.id;
45
+ if (!columnId) return;
46
+ const input = queryInputRef.current;
47
+ if (!input) return;
48
+ const start = input.selectionStart ?? query.length;
49
+ const end = input.selectionEnd ?? query.length;
50
+ setQuery(query.slice(0, start) + columnId + query.slice(end));
51
+ const caret = start + columnId.length;
52
+ requestAnimationFrame(() => {
53
+ input.focus();
54
+ input.setSelectionRange(caret, caret);
55
+ });
56
+ }
57
+
58
+ function executeQuery(query: string) {
59
+ const table = eventRunQuery.table;
60
+ if (!table) return;
61
+ const grid = table.grid;
62
+ if (!grid) return;
63
+ const dataView: SlickDataView = grid.getData();
64
+ const items = dataView.getItems();
65
+ const itemsCopy = [];
66
+ const fields = Object.keys(columnsHash);
67
+ for (const item of items) {
68
+ const newItem: Record<string, string | number | boolean> = {};
69
+ for (const field of fields) {
70
+ newItem[field] = item[field];
71
+ }
72
+ itemsCopy.push(newItem);
73
+ }
74
+ const gvizTable = new GvizTable(itemsCopy);
75
+ const run = gvizTable.query(query);
76
+ const newItems = run.toObjects();
77
+ setItems(newItems);
78
+ setColumns(
79
+ Object.keys(newItems[0] || {}).map(
80
+ (key): IColumn => ({
81
+ id: columnsHash[key].id,
82
+ field: columnsHash[key].field,
83
+ name: columnsHash[key].name,
84
+ formatter: columnsHash[key].formatter,
85
+ cssClass: columnsHash[key].cssClass,
86
+ }),
87
+ ),
88
+ );
89
+ setIsExpanded(true);
90
+ localStore.queries.set(tableId, query);
91
+ }
92
+
93
+ useSubscribeToEvent(setIsOpened, tableId);
94
+ useResizeCanvas(isExpanded);
95
+
96
+ if (!isOpened) return null;
97
+
98
+ return (
99
+ <Styled.Drawer
100
+ anchor={"bottom"}
101
+ open={isOpened}
102
+ onClose={closeDrawer}
103
+ disablePortal
104
+ isExpanded={isExpanded}
105
+ >
106
+ <QueryHistory
107
+ executeQuery={executeQuery}
108
+ query={query}
109
+ setQuery={setQuery}
110
+ />
111
+ <Box>
112
+ <Styled.Header>
113
+ <Styled.Title variant={"h6"}>
114
+ Run query across table data
115
+ </Styled.Title>
116
+ <Box>
117
+ {isExpanded && (
118
+ <IconButton onClick={() => setIsExpanded(false)}>
119
+ <span className={"sgi sgi-minus"}></span>
120
+ </IconButton>
121
+ )}
122
+ {!isExpanded && (
123
+ <IconButton onClick={() => setIsExpanded(true)}>
124
+ <span className={"sgi sgi-arrow-expand"}></span>
125
+ </IconButton>
126
+ )}
127
+ <IconButton onClick={closeDrawer}>
128
+ <span className={"sgi sgi-close"}></span>
129
+ </IconButton>
130
+ </Box>
131
+ </Styled.Header>
132
+ <Styled.ContainerInput>
133
+ <Styled.TextField
134
+ id="query-input"
135
+ label="Query"
136
+ maxRows={10}
137
+ multiline
138
+ onChange={updateQuery}
139
+ inputRef={queryInputRef}
140
+ slotProps={{
141
+ input: {
142
+ endAdornment: !!query && (
143
+ <Styled.EndAdornment position={"end"}>
144
+ <Tooltip title={"Clear query"}>
145
+ <Styled.ClearButton
146
+ aria-label={"Clear query"}
147
+ onClick={clearQuery}
148
+ size={"small"}
149
+ >
150
+ <span className={"sgi sgi-close"}></span>
151
+ </Styled.ClearButton>
152
+ </Tooltip>
153
+ </Styled.EndAdornment>
154
+ ),
155
+ },
156
+ }}
157
+ value={query}
158
+ />
159
+ <Styled.Button
160
+ disabled={!query.trim()}
161
+ onClick={() => executeQuery(query)}
162
+ variant={"contained"}
163
+ >
164
+ Execute
165
+ </Styled.Button>
166
+ </Styled.ContainerInput>
167
+ <Box sx={{ display: "flex", columnGap: "1em", marginBottom: "1em" }}>
168
+ {Object.values(columnsHash).map(({ id, name }) => (
169
+ <Styled.ColumnName
170
+ key={id}
171
+ id={id as string}
172
+ onClick={pasteColumnId}
173
+ >
174
+ {`#${name}`}
175
+ </Styled.ColumnName>
176
+ ))}
177
+ </Box>
178
+ <Styled.ContainerTable isExpanded={isExpanded}>
179
+ {!!columns.length && (
180
+ <SlickgridTable
181
+ assignIds={true}
182
+ columns={columns}
183
+ items={items}
184
+ table={tableQuery}
185
+ />
186
+ )}
187
+ </Styled.ContainerTable>
188
+ </Box>
189
+ </Styled.Drawer>
190
+ );
191
+ };
192
+
193
+ interface Props {
194
+ tableId: string;
195
+ }