@vuu-ui/vuu-utils 2.1.19-beta.1 → 2.1.19-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -9
- package/src/Clock.js +43 -0
- package/src/PageVisibilityObserver.js +42 -0
- package/src/ScaledDecimal.js +32 -0
- package/src/ShellContext.js +5 -0
- package/src/ThemeProvider.js +56 -0
- package/src/array-utils.js +51 -0
- package/src/box-utils.js +51 -0
- package/src/broadcast-channel.js +0 -0
- package/src/column-utils.js +790 -0
- package/src/common-types.js +11 -0
- package/src/component-registry.js +83 -0
- package/src/context-definitions/DataContext.js +15 -0
- package/src/context-definitions/DataProvider.js +13 -0
- package/src/context-definitions/DataSourceProvider.js +18 -0
- package/src/context-definitions/WorkspaceContext.js +14 -0
- package/src/cookie-utils.js +15 -0
- package/src/css-utils.js +5 -0
- package/src/data-editing/DataEditingProvider.js +13 -0
- package/src/data-editing/EditButtons.js +32 -0
- package/src/data-editing/EditModeProvider.js +18 -0
- package/src/data-editing/EditSession.js +149 -0
- package/src/data-editing/edit-utils.js +37 -0
- package/src/data-editing/useEditableTable.js +76 -0
- package/src/data-utils.js +55 -0
- package/src/datasource/BaseDataSource.js +233 -0
- package/src/datasource/datasource-action-utils.js +6 -0
- package/src/datasource/datasource-filter-utils.js +27 -0
- package/src/datasource/datasource-utils.js +148 -0
- package/src/date/date-utils.js +80 -0
- package/src/date/dateTimePattern.js +17 -0
- package/src/date/formatter.js +101 -0
- package/src/date/index.js +4 -0
- package/src/date/types.js +27 -0
- package/src/debug-utils.js +25 -0
- package/src/event-emitter.js +78 -0
- package/src/feature-utils.js +86 -0
- package/src/filters/filter-utils.js +136 -0
- package/src/filters/filterAsQuery.js +70 -0
- package/src/filters/index.js +2 -0
- package/src/form-utils.js +69 -0
- package/src/formatting-utils.js +42 -0
- package/src/getUniqueId.js +2 -0
- package/src/group-utils.js +16 -0
- package/src/html-utils.js +108 -0
- package/src/index.js +77 -0
- package/src/input-utils.js +3 -0
- package/src/invariant.js +9 -0
- package/src/itemToString.js +9 -0
- package/src/json-types.js +0 -0
- package/src/json-utils.js +108 -0
- package/src/keyboard-utils.js +14 -0
- package/src/keyset.js +57 -0
- package/src/layout-types.js +0 -0
- package/src/list-utils.js +5 -0
- package/src/local-storage-utils.js +23 -0
- package/src/logging-utils.js +52 -0
- package/src/module-utils.js +2 -0
- package/src/nanoid/index.js +13 -0
- package/src/perf-utils.js +28 -0
- package/src/promise-utils.js +26 -0
- package/src/protocol-message-utils.js +68 -0
- package/src/range-utils.js +109 -0
- package/src/react-utils.js +64 -0
- package/src/round-decimal.js +83 -0
- package/src/row-utils.js +43 -0
- package/src/selection-utils.js +25 -0
- package/src/shell-layout-types.js +9 -0
- package/src/sort-utils.js +75 -0
- package/src/table-schema-utils.js +11 -0
- package/src/text-utils.js +13 -0
- package/src/theme-utils.js +21 -0
- package/src/tree-types.js +0 -0
- package/src/tree-utils.js +96 -0
- package/src/ts-utils.js +6 -0
- package/src/typeahead-utils.js +4 -0
- package/src/url-utils.js +12 -0
- package/src/useId.js +6 -0
- package/src/useLayoutEffectSkipFirst.js +9 -0
- package/src/useResizeObserver.js +122 -0
- package/src/useStateRef.js +21 -0
- package/src/user-types.js +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { parseFilter } from "@vuu-ui/vuu-filter-parser";
|
|
2
|
+
import { EventEmitter } from "../event-emitter.js";
|
|
3
|
+
import { uuid } from "../nanoid/index.js";
|
|
4
|
+
import { isConfigChanged, stripVisualLink, vanillaConfig, withConfigDefaults } from "./datasource-utils.js";
|
|
5
|
+
import { Range } from "../range-utils.js";
|
|
6
|
+
import { filterAsQuery } from "../filters/index.js";
|
|
7
|
+
const defaultSuspenseProps = {
|
|
8
|
+
escalateToDisable: true
|
|
9
|
+
};
|
|
10
|
+
class BaseDataSource extends EventEmitter {
|
|
11
|
+
viewport;
|
|
12
|
+
_clientCallback;
|
|
13
|
+
_configWithVisualLink = vanillaConfig;
|
|
14
|
+
_impendingConfigWithVisualLink = void 0;
|
|
15
|
+
_range = Range(0, 0);
|
|
16
|
+
_size = 0;
|
|
17
|
+
_title;
|
|
18
|
+
_defaultSuspenseProps;
|
|
19
|
+
#freezeTimestamp = void 0;
|
|
20
|
+
#pageCount = 0;
|
|
21
|
+
awaitingConfirmationOfConfigChanges = false;
|
|
22
|
+
constructor({ aggregations, baseFilterSpec, columns, filterSpec, groupBy, sort, suspenseProps = defaultSuspenseProps, title, viewport }){
|
|
23
|
+
super();
|
|
24
|
+
this._configWithVisualLink = {
|
|
25
|
+
...this._configWithVisualLink,
|
|
26
|
+
aggregations: aggregations || this._configWithVisualLink.aggregations,
|
|
27
|
+
baseFilterSpec: baseFilterSpec || this._configWithVisualLink.baseFilterSpec,
|
|
28
|
+
columns: columns || this._configWithVisualLink.columns,
|
|
29
|
+
filterSpec: filterSpec || this._configWithVisualLink.filterSpec,
|
|
30
|
+
groupBy: groupBy || this._configWithVisualLink.groupBy,
|
|
31
|
+
sort: sort || this._configWithVisualLink.sort
|
|
32
|
+
};
|
|
33
|
+
this._defaultSuspenseProps = suspenseProps;
|
|
34
|
+
this._title = title;
|
|
35
|
+
this.viewport = viewport ?? "";
|
|
36
|
+
}
|
|
37
|
+
subscribe({ baseFilterSpec, columns, aggregations, range, sort, groupBy, filterSpec, viewport = this.viewport || (this.viewport = uuid()) }, callback) {
|
|
38
|
+
this._clientCallback = callback;
|
|
39
|
+
this.viewport = viewport;
|
|
40
|
+
if (aggregations || baseFilterSpec || columns || filterSpec || groupBy || sort) this._configWithVisualLink = {
|
|
41
|
+
...this._configWithVisualLink,
|
|
42
|
+
aggregations: aggregations || this._configWithVisualLink.aggregations,
|
|
43
|
+
baseFilterSpec: baseFilterSpec || this._configWithVisualLink.baseFilterSpec,
|
|
44
|
+
columns: columns || this._configWithVisualLink.columns,
|
|
45
|
+
filterSpec: filterSpec || this._configWithVisualLink.filterSpec,
|
|
46
|
+
groupBy: groupBy || this._configWithVisualLink.groupBy,
|
|
47
|
+
sort: sort || this._configWithVisualLink.sort
|
|
48
|
+
};
|
|
49
|
+
if (range) {
|
|
50
|
+
this._range = range;
|
|
51
|
+
this.emit("range", range);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
get aggregations() {
|
|
55
|
+
return this._configWithVisualLink.aggregations;
|
|
56
|
+
}
|
|
57
|
+
set aggregations(aggregations) {
|
|
58
|
+
this.config = {
|
|
59
|
+
...this._configWithVisualLink,
|
|
60
|
+
aggregations
|
|
61
|
+
};
|
|
62
|
+
this.emit("config", this._configWithVisualLink, this.range);
|
|
63
|
+
}
|
|
64
|
+
get baseFilter() {
|
|
65
|
+
return this._configWithVisualLink.baseFilterSpec;
|
|
66
|
+
}
|
|
67
|
+
set baseFilter(baseFilter) {
|
|
68
|
+
this.config = {
|
|
69
|
+
...this._configWithVisualLink,
|
|
70
|
+
baseFilterSpec: baseFilter
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
get columns() {
|
|
74
|
+
return this._configWithVisualLink.columns;
|
|
75
|
+
}
|
|
76
|
+
set columns(columns) {
|
|
77
|
+
this.config = {
|
|
78
|
+
...this._configWithVisualLink,
|
|
79
|
+
columns
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
get filter() {
|
|
83
|
+
return this._configWithVisualLink.filterSpec;
|
|
84
|
+
}
|
|
85
|
+
set filter(filter) {
|
|
86
|
+
this.config = {
|
|
87
|
+
...this._configWithVisualLink,
|
|
88
|
+
filterSpec: filter
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
setFilter(filter) {
|
|
92
|
+
const dataSourceFilter = {
|
|
93
|
+
filter: filterAsQuery(filter),
|
|
94
|
+
filterStruct: filter
|
|
95
|
+
};
|
|
96
|
+
this.filter = dataSourceFilter;
|
|
97
|
+
}
|
|
98
|
+
clearFilter() {
|
|
99
|
+
this.filter = {
|
|
100
|
+
filter: ""
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
get isAwaitingConfirmationOfConfigChange() {
|
|
104
|
+
return void 0 !== this._impendingConfigWithVisualLink;
|
|
105
|
+
}
|
|
106
|
+
confirmConfigChange() {
|
|
107
|
+
if (this._impendingConfigWithVisualLink) {
|
|
108
|
+
this._configWithVisualLink = this._impendingConfigWithVisualLink;
|
|
109
|
+
this._impendingConfigWithVisualLink = void 0;
|
|
110
|
+
this.emit("config", this._configWithVisualLink, this.range, true);
|
|
111
|
+
} else throw Error("[BaseDataSource], unexpected call to confirmConfigChange, no changes pending");
|
|
112
|
+
}
|
|
113
|
+
get config() {
|
|
114
|
+
return stripVisualLink(this._impendingConfigWithVisualLink ?? this._configWithVisualLink);
|
|
115
|
+
}
|
|
116
|
+
set config(config) {
|
|
117
|
+
const confirmed = this.awaitingConfirmationOfConfigChanges ? true : void 0;
|
|
118
|
+
this.awaitingConfirmationOfConfigChanges = false;
|
|
119
|
+
const configChanges = this.applyConfig(config);
|
|
120
|
+
if (configChanges) requestAnimationFrame(()=>{
|
|
121
|
+
this.emit("config", this._configWithVisualLink, this.range, confirmed, configChanges);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
get impendingConfig() {
|
|
125
|
+
return this._impendingConfigWithVisualLink;
|
|
126
|
+
}
|
|
127
|
+
set impendingConfig(config) {
|
|
128
|
+
if (config) {
|
|
129
|
+
this.awaitingConfirmationOfConfigChanges = true;
|
|
130
|
+
const configChanges = this.applyConfig(config);
|
|
131
|
+
if (configChanges) this.emit("config", this.config, this.range, false, configChanges);
|
|
132
|
+
} else throw Error("[BaseDataSource] ''unsetting impendingConfig is not currently supported");
|
|
133
|
+
}
|
|
134
|
+
get pageCount() {
|
|
135
|
+
return this.#pageCount;
|
|
136
|
+
}
|
|
137
|
+
set pageCount(pageCount) {
|
|
138
|
+
if (pageCount !== this.#pageCount) {
|
|
139
|
+
this.#pageCount = pageCount;
|
|
140
|
+
this.emit("page-count", pageCount);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
get range() {
|
|
144
|
+
return this._range;
|
|
145
|
+
}
|
|
146
|
+
set range(range) {
|
|
147
|
+
if (range.from !== this._range.from || range.to !== this._range.to) {
|
|
148
|
+
this._range = range;
|
|
149
|
+
this.pageCount = Math.ceil(this._size / (range.to - range.from));
|
|
150
|
+
this.rangeRequest(range.withBuffer);
|
|
151
|
+
requestAnimationFrame(()=>{
|
|
152
|
+
this.emit("range", range);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
get size() {
|
|
157
|
+
return this._size;
|
|
158
|
+
}
|
|
159
|
+
set size(size) {
|
|
160
|
+
this._size = size;
|
|
161
|
+
if (0 !== this.range.to) {
|
|
162
|
+
const pageCount = Math.ceil(size / (this.range.to - this.range.from));
|
|
163
|
+
this.pageCount = pageCount;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
get sort() {
|
|
167
|
+
return this._configWithVisualLink.sort;
|
|
168
|
+
}
|
|
169
|
+
set sort(sort) {
|
|
170
|
+
this.config = {
|
|
171
|
+
...this._configWithVisualLink,
|
|
172
|
+
sort
|
|
173
|
+
};
|
|
174
|
+
this.emit("config", this._configWithVisualLink, this.range);
|
|
175
|
+
}
|
|
176
|
+
get title() {
|
|
177
|
+
return this._title ?? "";
|
|
178
|
+
}
|
|
179
|
+
set title(title) {
|
|
180
|
+
this._title = title;
|
|
181
|
+
this.emit("title-changed", this.viewport ?? "", title);
|
|
182
|
+
}
|
|
183
|
+
applyConfig(config, preserveExistingConfigAttributes = false) {
|
|
184
|
+
const { noChanges, ...otherChanges } = isConfigChanged(this._configWithVisualLink, config);
|
|
185
|
+
if (true !== noChanges) {
|
|
186
|
+
if (config) {
|
|
187
|
+
const newConfig = config?.filterSpec?.filter && config?.filterSpec.filterStruct === void 0 ? {
|
|
188
|
+
...config,
|
|
189
|
+
filterSpec: {
|
|
190
|
+
filter: config.filterSpec.filter,
|
|
191
|
+
filterStruct: parseFilter(config.filterSpec.filter)
|
|
192
|
+
}
|
|
193
|
+
} : config;
|
|
194
|
+
if (preserveExistingConfigAttributes) if (this.awaitingConfirmationOfConfigChanges) this._impendingConfigWithVisualLink = {
|
|
195
|
+
...this._configWithVisualLink,
|
|
196
|
+
...config
|
|
197
|
+
};
|
|
198
|
+
else {
|
|
199
|
+
this._impendingConfigWithVisualLink = void 0;
|
|
200
|
+
this._configWithVisualLink = {
|
|
201
|
+
...this._configWithVisualLink,
|
|
202
|
+
...config
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
else if (this.awaitingConfirmationOfConfigChanges) this._impendingConfigWithVisualLink = withConfigDefaults(newConfig);
|
|
206
|
+
else {
|
|
207
|
+
this._impendingConfigWithVisualLink = void 0;
|
|
208
|
+
this._configWithVisualLink = withConfigDefaults(newConfig);
|
|
209
|
+
}
|
|
210
|
+
return otherChanges;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
freeze() {
|
|
215
|
+
if (this.isFrozen) throw Error("[BaseDataSource] cannot freeze, dataSource is already frozen");
|
|
216
|
+
this.#freezeTimestamp = new Date().getTime();
|
|
217
|
+
this.emit("freeze", true, this.#freezeTimestamp);
|
|
218
|
+
}
|
|
219
|
+
unfreeze() {
|
|
220
|
+
if (this.isFrozen) {
|
|
221
|
+
const freezeTimestamp = this.#freezeTimestamp;
|
|
222
|
+
this.#freezeTimestamp = void 0;
|
|
223
|
+
this.emit("freeze", false, freezeTimestamp);
|
|
224
|
+
} else throw Error("[BaseDataSource] cannot freeze, dataSource is already frozen");
|
|
225
|
+
}
|
|
226
|
+
get freezeTimestamp() {
|
|
227
|
+
return this.#freezeTimestamp;
|
|
228
|
+
}
|
|
229
|
+
get isFrozen() {
|
|
230
|
+
return "number" == typeof this.#freezeTimestamp;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
export { BaseDataSource, defaultSuspenseProps };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
const isVisualLinksAction = (action)=>"vuu-links" === action.type;
|
|
2
|
+
const isVisualLinkCreatedAction = (action)=>"vuu-link-created" === action.type;
|
|
3
|
+
const isVisualLinkRemovedAction = (action)=>"vuu-link-removed" === action.type;
|
|
4
|
+
const isViewportMenusAction = (action)=>"vuu-menu" === action.type;
|
|
5
|
+
const isVuuFeatureAction = (action)=>isViewportMenusAction(action) || isVisualLinksAction(action);
|
|
6
|
+
export { isViewportMenusAction, isVisualLinkCreatedAction, isVisualLinkRemovedAction, isVisualLinksAction, isVuuFeatureAction };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { parseFilter } from "@vuu-ui/vuu-filter-parser";
|
|
2
|
+
const combineFilters = ({ baseFilterSpec, filterSpec, ...config })=>{
|
|
3
|
+
if (void 0 === baseFilterSpec || "" === baseFilterSpec.filter) if (filterSpec.filterStruct || "" === filterSpec.filter) return {
|
|
4
|
+
...config,
|
|
5
|
+
filterSpec
|
|
6
|
+
};
|
|
7
|
+
else return {
|
|
8
|
+
...config,
|
|
9
|
+
filterSpec: {
|
|
10
|
+
filter: filterSpec.filter,
|
|
11
|
+
filterStruct: parseFilter(filterSpec.filter)
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
{
|
|
15
|
+
const baseFilterQuery = baseFilterSpec.filter;
|
|
16
|
+
const combinedFilter = filterSpec.filter.length > 0 && baseFilterQuery.length > 0 ? `${filterSpec.filter} and ${baseFilterQuery}` : filterSpec.filter || baseFilterQuery;
|
|
17
|
+
const newConfig = {
|
|
18
|
+
...config,
|
|
19
|
+
filterSpec: {
|
|
20
|
+
filter: combinedFilter,
|
|
21
|
+
filterStruct: combinedFilter.length > 0 ? parseFilter(combinedFilter) : void 0
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return newConfig;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export { combineFilters };
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
const NoFilter = {
|
|
2
|
+
filter: ""
|
|
3
|
+
};
|
|
4
|
+
const NoSort = {
|
|
5
|
+
sortDefs: []
|
|
6
|
+
};
|
|
7
|
+
const vanillaConfig = {
|
|
8
|
+
aggregations: [],
|
|
9
|
+
columns: [],
|
|
10
|
+
filterSpec: NoFilter,
|
|
11
|
+
groupBy: [],
|
|
12
|
+
sort: NoSort
|
|
13
|
+
};
|
|
14
|
+
const stripVisualLink = (configWithVisualLink)=>{
|
|
15
|
+
if (!configWithVisualLink.visualLink) return configWithVisualLink;
|
|
16
|
+
{
|
|
17
|
+
const { visualLink, ...config } = configWithVisualLink;
|
|
18
|
+
return config;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const equivalentAggregations = ({ aggregations: agg1 }, { aggregations: agg2 })=>void 0 === agg1 && agg2?.length === 0 || void 0 === agg2 && agg1?.length === 0;
|
|
22
|
+
const equivalentColumns = ({ columns: cols1 }, { columns: cols2 })=>void 0 === cols1 && cols2?.length === 0 || void 0 === cols2 && cols1?.length === 0;
|
|
23
|
+
const equivalentFilter = ({ filterSpec: f1 }, { filterSpec: f2 })=>void 0 === f1 && f2?.filter === "" || void 0 === f2 && f1?.filter === "";
|
|
24
|
+
const equivalentGroupBy = ({ groupBy: val1 }, { groupBy: val2 })=>void 0 === val1 && val2?.length === 0 || void 0 === val2 && val1?.length === 0;
|
|
25
|
+
const equivalentSort = ({ sort: s1 }, { sort: s2 })=>void 0 === s1 && s2?.sortDefs.length === 0 || void 0 === s2 && s1?.sortDefs.length === 0;
|
|
26
|
+
const exactlyTheSame = (a, b)=>{
|
|
27
|
+
if (a === b) return true;
|
|
28
|
+
if (void 0 === a && void 0 === b) return true;
|
|
29
|
+
return false;
|
|
30
|
+
};
|
|
31
|
+
const isAggregationsChanged = (config, newConfig)=>{
|
|
32
|
+
const { aggregations: agg1 } = config;
|
|
33
|
+
const { aggregations: agg2 } = newConfig;
|
|
34
|
+
if (exactlyTheSame(agg1, agg2) || equivalentAggregations(config, newConfig)) return false;
|
|
35
|
+
if (void 0 === agg1 || void 0 === agg2) return true;
|
|
36
|
+
if (agg1.length !== agg2.length) return true;
|
|
37
|
+
return agg1.some(({ column, aggType }, i)=>column !== agg2[i].column || aggType !== agg2[i].aggType);
|
|
38
|
+
};
|
|
39
|
+
const isColumnsChanged = (config, newConfig)=>{
|
|
40
|
+
const { columns: cols1 } = config;
|
|
41
|
+
const { columns: cols2 } = newConfig;
|
|
42
|
+
if (exactlyTheSame(cols1, cols2) || equivalentColumns(config, newConfig)) return false;
|
|
43
|
+
if (void 0 === cols1 || void 0 === cols2) return true;
|
|
44
|
+
if (cols1?.length !== cols2?.length) return true;
|
|
45
|
+
return cols1.some((column, i)=>column !== cols2?.[i]);
|
|
46
|
+
};
|
|
47
|
+
const isBaseFilterChanged = (c1, c2)=>{
|
|
48
|
+
if (equivalentFilter(c1, c2)) return false;
|
|
49
|
+
return c1.baseFilterSpec?.filter !== c2.baseFilterSpec?.filter;
|
|
50
|
+
};
|
|
51
|
+
const isFilterChanged = (c1, c2)=>{
|
|
52
|
+
if (equivalentFilter(c1, c2)) return false;
|
|
53
|
+
return c1.filterSpec?.filter !== c2.filterSpec?.filter;
|
|
54
|
+
};
|
|
55
|
+
const isGroupByChanged = (config, newConfig)=>{
|
|
56
|
+
const { groupBy: g1 } = config;
|
|
57
|
+
const { groupBy: g2 } = newConfig;
|
|
58
|
+
if (exactlyTheSame(g1, g2) || equivalentGroupBy(config, newConfig)) return false;
|
|
59
|
+
if (void 0 === g1 || void 0 === g2) return true;
|
|
60
|
+
if (g1?.length !== g2?.length) return true;
|
|
61
|
+
return g1.some((column, i)=>column !== g2?.[i]);
|
|
62
|
+
};
|
|
63
|
+
const isSortChanged = (config, newConfig)=>{
|
|
64
|
+
const { sort: s1 } = config;
|
|
65
|
+
const { sort: s2 } = newConfig;
|
|
66
|
+
if (exactlyTheSame(s1, s2) || equivalentSort(config, newConfig)) return false;
|
|
67
|
+
if (void 0 === s1 || void 0 === s2) return true;
|
|
68
|
+
if (s1?.sortDefs.length !== s2?.sortDefs.length) return true;
|
|
69
|
+
return s1.sortDefs.some(({ column, sortType }, i)=>column !== s2.sortDefs[i].column || sortType !== s2.sortDefs[i].sortType);
|
|
70
|
+
};
|
|
71
|
+
const isVisualLinkChanged = ({ visualLink: v1 }, { visualLink: v2 })=>{
|
|
72
|
+
if (exactlyTheSame(v1, v2)) return false;
|
|
73
|
+
if (void 0 === v1 || void 0 === v2) return true;
|
|
74
|
+
return v1.label !== v2.label || v2.parentVpId !== v2.parentVpId;
|
|
75
|
+
};
|
|
76
|
+
const NO_CONFIG_CHANGES = {
|
|
77
|
+
aggregationsChanged: false,
|
|
78
|
+
baseFilterChanged: false,
|
|
79
|
+
columnsChanged: false,
|
|
80
|
+
filterChanged: false,
|
|
81
|
+
groupByChanged: false,
|
|
82
|
+
noChanges: true,
|
|
83
|
+
sortChanged: false,
|
|
84
|
+
visualLinkChanged: false
|
|
85
|
+
};
|
|
86
|
+
const isConfigChanged = (config, newConfig)=>{
|
|
87
|
+
if (exactlyTheSame(config, newConfig)) return NO_CONFIG_CHANGES;
|
|
88
|
+
if (void 0 === config && void 0 == newConfig) return NO_CONFIG_CHANGES;
|
|
89
|
+
if (void 0 === config) return isConfigChanged({}, newConfig);
|
|
90
|
+
if (void 0 === newConfig) return isConfigChanged(config, {});
|
|
91
|
+
const aggregationsChanged = isAggregationsChanged(config, newConfig);
|
|
92
|
+
const baseFilterChanged = isBaseFilterChanged(config, newConfig);
|
|
93
|
+
const columnsChanged = isColumnsChanged(config, newConfig);
|
|
94
|
+
const filterChanged = isFilterChanged(config, newConfig);
|
|
95
|
+
const groupByChanged = isGroupByChanged(config, newConfig);
|
|
96
|
+
const sortChanged = isSortChanged(config, newConfig);
|
|
97
|
+
const visualLinkChanged = isVisualLinkChanged(config, newConfig);
|
|
98
|
+
const noChanges = !(aggregationsChanged || baseFilterChanged || columnsChanged || filterChanged || groupByChanged || sortChanged || visualLinkChanged);
|
|
99
|
+
return {
|
|
100
|
+
aggregationsChanged,
|
|
101
|
+
baseFilterChanged,
|
|
102
|
+
columnsChanged,
|
|
103
|
+
filterChanged,
|
|
104
|
+
groupByChanged,
|
|
105
|
+
noChanges,
|
|
106
|
+
sortChanged,
|
|
107
|
+
visualLinkChanged
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
const hasGroupBy = (config)=>void 0 !== config && void 0 !== config.groupBy && config.groupBy.length > 0;
|
|
111
|
+
const hasBaseFilter = (config)=>config?.baseFilterSpec !== void 0 && config.baseFilterSpec.filter.length > 0;
|
|
112
|
+
const hasFilter = (config)=>config?.filterSpec !== void 0 && config.filterSpec.filter.length > 0;
|
|
113
|
+
const hasSort = (config)=>config?.sort !== void 0 && Array.isArray(config.sort?.sortDefs) && config.sort.sortDefs.length > 0;
|
|
114
|
+
const isTypeaheadSuggestionProvider = (source)=>"function" == typeof source["getTypeaheadSuggestions"];
|
|
115
|
+
const isTableSchemaMessage = (message)=>"TABLE_META_RESP" === message.type;
|
|
116
|
+
const isConnectionQualityMetrics = (msg)=>"connection-metrics" === msg.type;
|
|
117
|
+
const messageHasResult = (msg)=>void 0 !== msg.result;
|
|
118
|
+
const isVisualLinkMessage = (msg)=>msg.type.endsWith("_VISUAL_LINK");
|
|
119
|
+
const isVisualLinksMessage = (msg)=>"vuu-links" === msg.type;
|
|
120
|
+
const isViewportMessage = (msg)=>"viewport" in msg;
|
|
121
|
+
const messageHasDataRows = (message)=>"viewport-update" === message.type && Array.isArray(message.rows);
|
|
122
|
+
const messageHasSize = (message)=>"viewport-update" === message.type && "number" == typeof message.size;
|
|
123
|
+
const withConfigDefaults = (config)=>{
|
|
124
|
+
if (config.aggregations && config.baseFilterSpec && config.columns && config.filterSpec && config.groupBy && config.sort) return config;
|
|
125
|
+
{
|
|
126
|
+
const { aggregations = [], baseFilterSpec: baseFilter = {
|
|
127
|
+
filter: ""
|
|
128
|
+
}, columns = [], filterSpec: filter = {
|
|
129
|
+
filter: ""
|
|
130
|
+
}, groupBy = [], sort = {
|
|
131
|
+
sortDefs: []
|
|
132
|
+
}, visualLink } = config;
|
|
133
|
+
return {
|
|
134
|
+
aggregations,
|
|
135
|
+
baseFilterSpec: baseFilter,
|
|
136
|
+
columns,
|
|
137
|
+
filterSpec: filter,
|
|
138
|
+
groupBy,
|
|
139
|
+
sort,
|
|
140
|
+
visualLink
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
const dataSourceRowToEntity = (row, columnMap)=>Object.entries(columnMap).reduce((entity, [name, index])=>({
|
|
145
|
+
...entity,
|
|
146
|
+
[name]: row[index]
|
|
147
|
+
}), {});
|
|
148
|
+
export { NO_CONFIG_CHANGES, NoFilter, NoSort, dataSourceRowToEntity, hasBaseFilter, hasFilter, hasGroupBy, hasSort, isBaseFilterChanged, isConfigChanged, isConnectionQualityMetrics, isFilterChanged, isGroupByChanged, isTableSchemaMessage, isTypeaheadSuggestionProvider, isViewportMessage, isVisualLinkMessage, isVisualLinksMessage, messageHasDataRows, messageHasResult, messageHasSize, stripVisualLink, vanillaConfig, withConfigDefaults };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { CalendarDate } from "@internationalized/date";
|
|
2
|
+
function toCalendarDate(d) {
|
|
3
|
+
return new CalendarDate(d.getFullYear(), d.getMonth() + 1, d.getDate());
|
|
4
|
+
}
|
|
5
|
+
const zeroTime = "00:00:00";
|
|
6
|
+
const zeroTimeUnit = "00";
|
|
7
|
+
function incrementTimeUnitValue(unit, value) {
|
|
8
|
+
const num = parseInt(value);
|
|
9
|
+
if ("hours" === unit && num < 23) return `${num + 1}`.padStart(2, "0").slice(-2);
|
|
10
|
+
if ("hours" === unit && 23 === num) return "00";
|
|
11
|
+
if (num < 59) return `${num + 1}`.padStart(2, "0").slice(-2);
|
|
12
|
+
if (59 === num) return "00";
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
function decrementTimeUnitValue(unit, value) {
|
|
16
|
+
const num = parseInt(value);
|
|
17
|
+
if ("hours" === unit && num > 0) return `${num - 1}`.padStart(2, "0").slice(-2);
|
|
18
|
+
if ("hours" === unit && 0 === num) return "23";
|
|
19
|
+
if (num > 0) return `${num - 1}`.padStart(2, "0").slice(-2);
|
|
20
|
+
if (0 === num) return "59";
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function updateTimeString(timeString, unit, value) {
|
|
24
|
+
const newTimeString = "hours" === unit ? value.concat(timeString.slice(2)) : "minutes" === unit ? timeString.slice(0, 3).concat(value).concat(timeString.slice(5)) : timeString.slice(0, 6).concat(value);
|
|
25
|
+
if (isValidTimeString(newTimeString)) return newTimeString;
|
|
26
|
+
throw Error(`[date-utils] udateTimeSting invalid result ${newTimeString}`);
|
|
27
|
+
}
|
|
28
|
+
const validTimePattern = /(?:[0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]/;
|
|
29
|
+
const isValidTimeString = (value)=>"string" == typeof value && validTimePattern.test(value);
|
|
30
|
+
function asTimeString(value, allowUndefined = false) {
|
|
31
|
+
if (void 0 === value) if (allowUndefined) return value;
|
|
32
|
+
else throw Error("[date-utils] asTimeString, value cannot be undefined");
|
|
33
|
+
if (isValidTimeString(value)) return value;
|
|
34
|
+
if ("number" == typeof value) return Time.millisToTimeString(value);
|
|
35
|
+
if ("string" == typeof value) {
|
|
36
|
+
const valueAsInt = parseInt(value);
|
|
37
|
+
if (!isNaN(valueAsInt)) return Time.millisToTimeString(valueAsInt);
|
|
38
|
+
} else throw Error(`[date-utils] asTimeString, value ${value} is not valid TimeString`);
|
|
39
|
+
}
|
|
40
|
+
const padZero = (val)=>`${val}`.padStart(2, "0");
|
|
41
|
+
class TimeImpl {
|
|
42
|
+
#hours;
|
|
43
|
+
#minutes;
|
|
44
|
+
#seconds;
|
|
45
|
+
constructor(timeString){
|
|
46
|
+
const [hours, minutes, seconds] = timeString.split(":");
|
|
47
|
+
this.#hours = parseInt(hours);
|
|
48
|
+
this.#minutes = parseInt(minutes);
|
|
49
|
+
this.#seconds = parseInt(seconds);
|
|
50
|
+
}
|
|
51
|
+
get hours() {
|
|
52
|
+
return this.#hours;
|
|
53
|
+
}
|
|
54
|
+
get minutes() {
|
|
55
|
+
return this.#minutes;
|
|
56
|
+
}
|
|
57
|
+
get seconds() {
|
|
58
|
+
return this.#seconds;
|
|
59
|
+
}
|
|
60
|
+
asDate(date) {
|
|
61
|
+
const dt = void 0 === date ? new Date() : "string" == typeof date ? new Date(date) : date;
|
|
62
|
+
dt.setHours(this.#hours);
|
|
63
|
+
dt.setMinutes(this.#minutes);
|
|
64
|
+
dt.setSeconds(this.seconds);
|
|
65
|
+
dt.setMilliseconds(0);
|
|
66
|
+
return dt;
|
|
67
|
+
}
|
|
68
|
+
toString() {
|
|
69
|
+
return Time.toString(this.#hours, this.#minutes, this.#seconds);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const Time = (timeString)=>new TimeImpl(timeString);
|
|
73
|
+
Time.millisToTimeString = (timestamp)=>new Date(timestamp).toTimeString().slice(0, 8);
|
|
74
|
+
Time.toString = (hours, minutes, seconds)=>`${padZero(hours)}:${padZero(minutes)}:${padZero(seconds)}`;
|
|
75
|
+
Time.isDateInMillis = (dtInMillis)=>{
|
|
76
|
+
const n = "number" == typeof dtInMillis ? dtInMillis : Number(dtInMillis);
|
|
77
|
+
if (!Number.isFinite(n) || !Number.isInteger(n)) return false;
|
|
78
|
+
return new Date(n).getTime() === n;
|
|
79
|
+
};
|
|
80
|
+
export { Time, asTimeString, decrementTimeUnitValue, incrementTimeUnitValue, isValidTimeString, toCalendarDate, updateTimeString, zeroTime, zeroTimeUnit };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { isTypeDescriptor } from "../column-utils.js";
|
|
2
|
+
import { isDateTimePattern } from "./types.js";
|
|
3
|
+
const defaultPatternsByType = {
|
|
4
|
+
time: "hh:mm:ss",
|
|
5
|
+
date: "dd.mm.yyyy"
|
|
6
|
+
};
|
|
7
|
+
const fallbackDateTimePattern = {
|
|
8
|
+
date: defaultPatternsByType["date"],
|
|
9
|
+
time: defaultPatternsByType["time"]
|
|
10
|
+
};
|
|
11
|
+
function dateTimePattern(type) {
|
|
12
|
+
if (isTypeDescriptor(type)) {
|
|
13
|
+
if (type.formatting && isDateTimePattern(type.formatting.pattern)) return type.formatting.pattern;
|
|
14
|
+
}
|
|
15
|
+
return fallbackDateTimePattern;
|
|
16
|
+
}
|
|
17
|
+
export { dateTimePattern, defaultPatternsByType, fallbackDateTimePattern };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { DateFormatter } from "@internationalized/date";
|
|
2
|
+
const baseTimeFormatOptions = {
|
|
3
|
+
hour: "2-digit",
|
|
4
|
+
minute: "2-digit",
|
|
5
|
+
second: "2-digit"
|
|
6
|
+
};
|
|
7
|
+
const formatConfigByTimePatterns = {
|
|
8
|
+
"hh:mm:ss": {
|
|
9
|
+
locale: "en-GB",
|
|
10
|
+
options: {
|
|
11
|
+
...baseTimeFormatOptions,
|
|
12
|
+
hour12: false
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"hh:mm:ss a": {
|
|
16
|
+
locale: "en-GB",
|
|
17
|
+
options: {
|
|
18
|
+
...baseTimeFormatOptions,
|
|
19
|
+
hour12: true
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"hh:mm:ss.ms": {
|
|
23
|
+
locale: "en-GB",
|
|
24
|
+
options: {
|
|
25
|
+
...baseTimeFormatOptions,
|
|
26
|
+
hour12: false,
|
|
27
|
+
fractionalSecondDigits: 3
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const baseDateFormatOptions = {
|
|
32
|
+
day: "2-digit",
|
|
33
|
+
month: "2-digit",
|
|
34
|
+
year: "numeric"
|
|
35
|
+
};
|
|
36
|
+
const formatConfigByDatePatterns = {
|
|
37
|
+
"dd.mm.yyyy": {
|
|
38
|
+
locale: "de-De",
|
|
39
|
+
options: {
|
|
40
|
+
...baseDateFormatOptions
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"dd/mm/yyyy": {
|
|
44
|
+
locale: "en-GB",
|
|
45
|
+
options: {
|
|
46
|
+
...baseDateFormatOptions
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"dd MMM yyyy": {
|
|
50
|
+
locale: "en-GB",
|
|
51
|
+
options: {
|
|
52
|
+
...baseDateFormatOptions,
|
|
53
|
+
month: "short"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"dd MMMM yyyy": {
|
|
57
|
+
locale: "en-GB",
|
|
58
|
+
options: {
|
|
59
|
+
...baseDateFormatOptions,
|
|
60
|
+
month: "long"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"mm/dd/yyyy": {
|
|
64
|
+
locale: "en-US",
|
|
65
|
+
options: {
|
|
66
|
+
...baseDateFormatOptions
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"MMM dd, yyyy": {
|
|
70
|
+
locale: "en-US",
|
|
71
|
+
options: {
|
|
72
|
+
...baseDateFormatOptions,
|
|
73
|
+
month: "short"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"MMMM dd, yyyy": {
|
|
77
|
+
locale: "en-US",
|
|
78
|
+
options: {
|
|
79
|
+
...baseDateFormatOptions,
|
|
80
|
+
month: "long"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const dateFormatterISO = {
|
|
85
|
+
format: (date)=>new Date(date - 60000 * date.getTimezoneOffset()).toISOString().replace(/T.*/, "")
|
|
86
|
+
};
|
|
87
|
+
function getDateFormatter({ locale, options }) {
|
|
88
|
+
return new DateFormatter(locale, options);
|
|
89
|
+
}
|
|
90
|
+
function getDateAndTimeFormatters({ date, time }) {
|
|
91
|
+
const out = [];
|
|
92
|
+
if ("yyyy-mm-dd" === date) out.push(dateFormatterISO);
|
|
93
|
+
else if (date) out.push(getDateFormatter(formatConfigByDatePatterns[date]));
|
|
94
|
+
if (time) out.push(getDateFormatter(formatConfigByTimePatterns[time]));
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
function formatDate(pattern) {
|
|
98
|
+
const formatters = getDateAndTimeFormatters(pattern);
|
|
99
|
+
return (d)=>formatters.map((f)=>f.format(d)).join(" ");
|
|
100
|
+
}
|
|
101
|
+
export { formatDate, getDateFormatter };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export * from "./formatter.js";
|
|
2
|
+
export { Time, asTimeString, decrementTimeUnitValue, incrementTimeUnitValue, isValidTimeString, toCalendarDate, updateTimeString, zeroTime, zeroTimeUnit } from "./date-utils.js";
|
|
3
|
+
export { dateTimePattern, defaultPatternsByType, fallbackDateTimePattern } from "./dateTimePattern.js";
|
|
4
|
+
export { dateTimeLabelByType, isDatePattern, isTimePattern, supportedDateTimePatterns } from "./types.js";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const supportedDatePatterns = [
|
|
2
|
+
"yyyy-mm-dd",
|
|
3
|
+
"dd.mm.yyyy",
|
|
4
|
+
"dd/mm/yyyy",
|
|
5
|
+
"dd MMM yyyy",
|
|
6
|
+
"dd MMMM yyyy",
|
|
7
|
+
"mm/dd/yyyy",
|
|
8
|
+
"MMM dd, yyyy",
|
|
9
|
+
"MMMM dd, yyyy"
|
|
10
|
+
];
|
|
11
|
+
const supportedTimePatterns = [
|
|
12
|
+
"hh:mm:ss",
|
|
13
|
+
"hh:mm:ss a",
|
|
14
|
+
"hh:mm:ss.ms"
|
|
15
|
+
];
|
|
16
|
+
const supportedDateTimePatterns = {
|
|
17
|
+
date: supportedDatePatterns,
|
|
18
|
+
time: supportedTimePatterns
|
|
19
|
+
};
|
|
20
|
+
const dateTimeLabelByType = {
|
|
21
|
+
date: "Date",
|
|
22
|
+
time: "Time"
|
|
23
|
+
};
|
|
24
|
+
const isDatePattern = (pattern)=>supportedDatePatterns.includes(pattern);
|
|
25
|
+
const isTimePattern = (pattern)=>supportedTimePatterns.includes(pattern);
|
|
26
|
+
const isDateTimePattern = (pattern)=>isDatePattern(pattern?.date) || isTimePattern(pattern?.time);
|
|
27
|
+
export { dateTimeLabelByType, isDatePattern, isDateTimePattern, isTimePattern, supportedDateTimePatterns };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { logger } from "./logging-utils.js";
|
|
2
|
+
const { debug: debug, debugEnabled: debugEnabled } = logger("range-monitor");
|
|
3
|
+
class RangeMonitor {
|
|
4
|
+
source;
|
|
5
|
+
range = {
|
|
6
|
+
from: 0,
|
|
7
|
+
to: 0
|
|
8
|
+
};
|
|
9
|
+
timestamp = 0;
|
|
10
|
+
constructor(source){
|
|
11
|
+
this.source = source;
|
|
12
|
+
}
|
|
13
|
+
isSet() {
|
|
14
|
+
return 0 !== this.timestamp;
|
|
15
|
+
}
|
|
16
|
+
set({ from, to }) {
|
|
17
|
+
const { timestamp } = this;
|
|
18
|
+
this.range.from = from;
|
|
19
|
+
this.range.to = to;
|
|
20
|
+
this.timestamp = performance.now();
|
|
21
|
+
if (!timestamp) return 0;
|
|
22
|
+
debugEnabled && debug(`<${this.source}> [${from}-${to}], ${(this.timestamp - timestamp).toFixed(0)} ms elapsed`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export { RangeMonitor };
|