@krak-stack/registry 0.1.39 → 0.1.41
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/README.md +158 -0
- package/dist/components/ui/data-table.d.ts +27 -10
- package/dist/components/ui/data-table.js +81 -36
- package/dist/components/ui/google-map.d.ts +14 -1
- package/dist/components/ui/google-map.js +97 -18
- package/dist/lib/query.d.ts +30 -3
- package/dist/lib/query.js +13 -3
- package/dist/services/opentelemetry/api.d.ts +1 -1
- package/dist/services/opentelemetry/api.js +165 -13
- package/dist/services/opentelemetry/browser.d.ts +21 -3
- package/dist/services/opentelemetry/browser.js +267 -21
- package/dist/services/opentelemetry/events.d.ts +37 -0
- package/dist/services/opentelemetry/schema.d.ts +44 -0
- package/dist/services/opentelemetry/server.d.ts +20 -0
- package/dist/services/opentelemetry/server.js +154 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -98,6 +98,164 @@ if (!import.meta.env.SSR) {
|
|
|
98
98
|
}
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
+
### Named events and page views
|
|
102
|
+
|
|
103
|
+
For workers, workflows, or CLIs without an HTTP server, provide `ServerOtlp.layer`
|
|
104
|
+
from `@krak-stack/registry/opentelemetry/server`. `HttpApiOtlp.layer` already
|
|
105
|
+
includes this layer alongside the browser proxy routes.
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { Effect } from "effect";
|
|
109
|
+
import { ServerOtlp } from "@krak-stack/registry/opentelemetry/server";
|
|
110
|
+
|
|
111
|
+
const program = ServerOtlp.track("app.order.completed", {
|
|
112
|
+
"order.id": "order-123",
|
|
113
|
+
}).pipe(Effect.provide(ServerOtlp.layer));
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Enable server events with `OTEL_LOGS_EXPORTER=otlp`, `OTEL_SERVICE_NAME`, and
|
|
117
|
+
`OTEL_EXPORTER_OTLP_ENDPOINT` (the exporter appends `/v1/logs`), or an explicit
|
|
118
|
+
`OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`. Signal-specific headers override
|
|
119
|
+
`OTEL_EXPORTER_OTLP_HEADERS`; `OTEL_SDK_DISABLED=true` disables export. Use a
|
|
120
|
+
long-lived application runtime to retain batching; dispose it on shutdown to
|
|
121
|
+
flush pending events.
|
|
122
|
+
|
|
123
|
+
Browser events are separately opt-in and do not enable application log export:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
BrowserOtlp.layer({ serviceName: "my-app-web", events: {} });
|
|
127
|
+
|
|
128
|
+
// Effects use the active BrowserOtlp.layer, even from a different calling runtime.
|
|
129
|
+
const telemetry = Effect.gen(function* () {
|
|
130
|
+
yield* BrowserOtlp.track("app.checkout.started", {
|
|
131
|
+
"checkout.source": "cart",
|
|
132
|
+
});
|
|
133
|
+
yield* BrowserOtlp.page({
|
|
134
|
+
name: "Documentation",
|
|
135
|
+
category: "Docs",
|
|
136
|
+
path: "/docs",
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
With `events: {}`, page views are automatic: one when the layer starts, then one
|
|
142
|
+
for each pathname change through `pushState`, `replaceState`, or `popstate`
|
|
143
|
+
(back/forward). Repeated same-path changes and query/hash-only changes are ignored.
|
|
144
|
+
History hooks and listeners are scoped and restored on disposal. Tracking follows
|
|
145
|
+
URL changes, not framework loader completion. The first page may be anonymous if
|
|
146
|
+
identity has not been set yet; identify does not retroactively change it.
|
|
147
|
+
|
|
148
|
+
Set `events: { pageViews: false }` to disable automatic tracking while retaining custom events.
|
|
149
|
+
Then call `page` (`pageView` alias) manually for route templates or application-specific
|
|
150
|
+
navigation timing. Do not also manually emit the same automatic page view.
|
|
151
|
+
Without `path`, it reads `location.pathname` when executed. It emits the
|
|
152
|
+
application-defined event `browser.page_view` with required attribute `url.path`,
|
|
153
|
+
stripping query strings and fragments. Supply sanitized paths or route templates
|
|
154
|
+
when paths contain personal information. No cookies or visitor/session IDs are
|
|
155
|
+
created. Only the pathname is captured; paths may still contain personal IDs.
|
|
156
|
+
|
|
157
|
+
### Browser identity
|
|
158
|
+
|
|
159
|
+
Call `BrowserOtlp.identify` when auth state becomes available or changes, and
|
|
160
|
+
`BrowserOtlp.identify(null)` on logout. These remain Effects, but the caller does not need
|
|
161
|
+
the browser exporter's services in its own runtime:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
const telemetry = Effect.gen(function* () {
|
|
165
|
+
yield* BrowserOtlp.identify({
|
|
166
|
+
userId: "user-123",
|
|
167
|
+
organizationId: "org-123",
|
|
168
|
+
});
|
|
169
|
+
yield* BrowserOtlp.track("app.checkout.started");
|
|
170
|
+
yield* BrowserOtlp.page({ path: "/checkout" });
|
|
171
|
+
yield* BrowserOtlp.identify(null);
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Identity is in memory per telemetry runtime, not cookies or local storage.
|
|
176
|
+
`identify` is best-effort and has no typed failure: invalid identity leaves the
|
|
177
|
+
previous identity unchanged and logs a warning without including supplied values.
|
|
178
|
+
`identify` replaces the complete identity; omitting an organization clears the
|
|
179
|
+
previous organization. It emits no event. Identity is copied into each future
|
|
180
|
+
event when recorded; changes and resets do not rewrite queued events. Identified
|
|
181
|
+
user/org attributes override per-call properties/options, while scoped log
|
|
182
|
+
annotations take precedence over identified identity. This applies only to event
|
|
183
|
+
telemetry, not automatic trace/log exporters, API request headers, or authorization.
|
|
184
|
+
Browser identity is client-supplied and untrusted; use trusted server events for
|
|
185
|
+
billing, authorization, audit trails, or tenant-isolated reporting. Re-identify
|
|
186
|
+
after a reload and update identity before recording events after an auth or
|
|
187
|
+
organization change. The OTLP proxy remains passthrough and never enriches identity.
|
|
188
|
+
|
|
189
|
+
Initialize the browser layer once on the application's long-lived runtime. After
|
|
190
|
+
it starts, `Effect.runPromise(BrowserOtlp.identify(...))` and
|
|
191
|
+
`Effect.runPromise(BrowserOtlp.track(...))` work from ordinary application code.
|
|
192
|
+
Event methods retain typed validation errors and the calling fiber's trace/log
|
|
193
|
+
context; `identify` handles validation failures internally.
|
|
194
|
+
Calls executed before startup or after disposal are no-ops; nothing is buffered.
|
|
195
|
+
If several browser layers are active, calls target the most recently started one;
|
|
196
|
+
use a single browser layer in normal applications. There is no analytics bridge,
|
|
197
|
+
React hook, or automatic identification.
|
|
198
|
+
|
|
199
|
+
### Event options
|
|
200
|
+
|
|
201
|
+
Both environments accept
|
|
202
|
+
`track(name, properties?, options?)`. Common options are explicit and per-call,
|
|
203
|
+
so server requests never share mutable visitor state:
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
const telemetry = Effect.gen(function* () {
|
|
207
|
+
yield* ServerOtlp.track(
|
|
208
|
+
"app.order.completed",
|
|
209
|
+
{ "order.total": 49 },
|
|
210
|
+
{
|
|
211
|
+
sessionId: "session-123",
|
|
212
|
+
messageId: "order-123-completed",
|
|
213
|
+
context: { "organization.id": "org-123", "app.locale": "en" },
|
|
214
|
+
},
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`context` and event properties become flat OTLP attributes; properties override
|
|
220
|
+
context on collision. Options `userId`, `anonymousId`, `sessionId`, and `messageId`
|
|
221
|
+
map to `user.id`, `analytics.anonymous_id`, `session.id`, and `log.record.uid`,
|
|
222
|
+
overriding properties with the same keys. Scoped `Effect.annotateLogs` annotations
|
|
223
|
+
are inherited automatically and take precedence over all per-call attributes.
|
|
224
|
+
In authenticated server handlers, `AuthMiddleware` already supplies `user.id` and
|
|
225
|
+
`organization.id`, so do not repeat them in `.track()` calls. Background jobs and
|
|
226
|
+
browser code can provide identity explicitly when needed. Annotations remain
|
|
227
|
+
fiber-scoped; no identity state is persisted by the event service.
|
|
228
|
+
Identifiers are optional; callers own
|
|
229
|
+
consent and identity lifecycle. Message IDs aid correlation, not guaranteed
|
|
230
|
+
deduplication. Optional `timestamp` accepts an Effect `DateTime.Utc` for delayed
|
|
231
|
+
events; the SDK still sets observed time to the time of recording. There is no
|
|
232
|
+
clock-skew correction. `page` accepts `properties` and these same `options`, plus
|
|
233
|
+
optional `name` and `category` mapped to application-defined
|
|
234
|
+
`analytics.page.name` and `analytics.page.category` attributes. It always owns
|
|
235
|
+
the sanitized `url.path`. The `analytics.*` fields and `browser.page_view` name
|
|
236
|
+
are project conventions, not standardized OpenTelemetry analytics semantics.
|
|
237
|
+
Group, Alias, profile storage, destination routing, and automatic
|
|
238
|
+
collection of IPs, user agents, page titles, referrers, and full URLs are not
|
|
239
|
+
implemented.
|
|
240
|
+
|
|
241
|
+
Both `.track(name, attributes?)` methods follow the
|
|
242
|
+
[OpenTelemetry event conventions](https://opentelemetry.io/docs/specs/semconv/general/events/):
|
|
243
|
+
records have the native `eventName` field, an occurrence timestamp, INFO severity
|
|
244
|
+
number (9), flat structured attributes, and no body. The SDK sets observed time
|
|
245
|
+
when it records the occurrence. Events inherit active trace/span IDs without
|
|
246
|
+
creating spans. Use stable domain-qualified names with no dynamic identifiers;
|
|
247
|
+
put changing values in attributes. Document each custom event's trigger and
|
|
248
|
+
required/optional attributes; include `error.type` for failures. These conventions
|
|
249
|
+
are still in development. Attribute values support strings, finite numbers,
|
|
250
|
+
booleans, and homogeneous arrays of those values. Invalid inputs fail with an
|
|
251
|
+
Effect schema error.
|
|
252
|
+
|
|
253
|
+
The logs proxy must be enabled with `OTEL_LOGS_EXPORTER=otlp` for browser events.
|
|
254
|
+
OTLP transports events; configure a collector and a logs backend such as Loki for
|
|
255
|
+
storage and Grafana dashboards. Browser flushing on hidden/pagehide is best
|
|
256
|
+
effort. Apply payload limits and rate limits at your public ingestion boundary,
|
|
257
|
+
avoid sensitive attributes, and keep high-cardinality fields out of Loki labels.
|
|
258
|
+
|
|
101
259
|
`@krak-stack/registry/service-notification` is the source-compatible direct
|
|
102
260
|
dispatcher. Use the separate `@krak-stack/notifications` package for a durable
|
|
103
261
|
inbox, package-owned migrations, persisted delivery jobs, retries, workers, and
|
|
@@ -32,10 +32,10 @@ export interface DataTableListItemContext<TData> {
|
|
|
32
32
|
}
|
|
33
33
|
export interface DataTableListOptions {
|
|
34
34
|
emptyLabel: ReactNode;
|
|
35
|
-
display?: "list" | "icon";
|
|
36
|
-
locale?: string;
|
|
37
|
-
messages?: DataTableMessageTranslations;
|
|
38
|
-
visibleCount?: number;
|
|
35
|
+
display?: "list" | "icon" | undefined;
|
|
36
|
+
locale?: string | undefined;
|
|
37
|
+
messages?: DataTableMessageTranslations | undefined;
|
|
38
|
+
visibleCount?: number | undefined;
|
|
39
39
|
}
|
|
40
40
|
export type DataTableListColumn<TData> = DataTableListOptions & {
|
|
41
41
|
/** Includes items not loaded in the preview; the dropdown only shows supplied items. */
|
|
@@ -76,8 +76,8 @@ interface EditableDataTableListCellProps extends DataTableListOptions {
|
|
|
76
76
|
totalCount?: number | undefined;
|
|
77
77
|
}
|
|
78
78
|
interface DataTableListCellActionsProps {
|
|
79
|
-
actionsLabel?: string;
|
|
80
|
-
itemActions?: readonly DataTableItemAction<DataTableListItem>[];
|
|
79
|
+
actionsLabel?: string | undefined;
|
|
80
|
+
itemActions?: readonly DataTableItemAction<DataTableListItem>[] | undefined;
|
|
81
81
|
}
|
|
82
82
|
export type DataTableListCellProps = DataTableListCellActionsProps & (EditableDataTableListCellProps | (DataTableListSummaryProps & {
|
|
83
83
|
options?: never;
|
|
@@ -206,6 +206,23 @@ export type DataTablePaginationFeature = false | {
|
|
|
206
206
|
rowCount: number;
|
|
207
207
|
pageSizes?: readonly number[];
|
|
208
208
|
};
|
|
209
|
+
export interface DataTableExportAction {
|
|
210
|
+
id: string;
|
|
211
|
+
label: string;
|
|
212
|
+
icon?: ReactNode;
|
|
213
|
+
disabled?: boolean;
|
|
214
|
+
/** The app owns fetching, authorization, field selection, and downloading. */
|
|
215
|
+
onExport: () => void | Promise<void>;
|
|
216
|
+
}
|
|
217
|
+
export interface DataTableExportFeature {
|
|
218
|
+
baseName: string;
|
|
219
|
+
/** Both scopes operate only on rows already supplied to the table. */
|
|
220
|
+
scope?: "currentPage" | "filteredRows";
|
|
221
|
+
/** Set false to offer only app-provided actions. Defaults to true. */
|
|
222
|
+
builtIn?: boolean;
|
|
223
|
+
actions?: readonly DataTableExportAction[];
|
|
224
|
+
onError?: (error: unknown, action: DataTableExportAction) => void;
|
|
225
|
+
}
|
|
209
226
|
export interface DataTableFeatures<TData> {
|
|
210
227
|
toolbar?: false | {
|
|
211
228
|
/** Additional `MenubarMenu` controls rendered at the start of the toolbar. */
|
|
@@ -228,10 +245,7 @@ export interface DataTableFeatures<TData> {
|
|
|
228
245
|
label?: string;
|
|
229
246
|
items: readonly DataTableRowAction<TData>[];
|
|
230
247
|
};
|
|
231
|
-
export?: false |
|
|
232
|
-
baseName: string;
|
|
233
|
-
scope?: "currentPage" | "filteredRows";
|
|
234
|
-
};
|
|
248
|
+
export?: false | DataTableExportFeature;
|
|
235
249
|
gallery?: false | {
|
|
236
250
|
name: string;
|
|
237
251
|
description?: string;
|
|
@@ -255,6 +269,7 @@ export type DataTableMessages = PaginationMessages & {
|
|
|
255
269
|
export: string;
|
|
256
270
|
exportCsv: string;
|
|
257
271
|
exportJson: string;
|
|
272
|
+
exportFailed?: string;
|
|
258
273
|
refresh: string;
|
|
259
274
|
view: string;
|
|
260
275
|
tableView: string;
|
|
@@ -295,6 +310,7 @@ export declare const dataTableMessages: (locale?: string, translations?: DataTab
|
|
|
295
310
|
export: string;
|
|
296
311
|
exportCsv: string;
|
|
297
312
|
exportJson: string;
|
|
313
|
+
exportFailed: string;
|
|
298
314
|
refresh: string;
|
|
299
315
|
view: string;
|
|
300
316
|
tableView: string;
|
|
@@ -332,6 +348,7 @@ export declare const dataTableMessages: (locale?: string, translations?: DataTab
|
|
|
332
348
|
export: string;
|
|
333
349
|
exportCsv: string;
|
|
334
350
|
exportJson: string;
|
|
351
|
+
exportFailed: string;
|
|
335
352
|
refresh: string;
|
|
336
353
|
view: string;
|
|
337
354
|
tableView: string;
|
|
@@ -993,6 +993,7 @@ var messages2 = {
|
|
|
993
993
|
export: "Export",
|
|
994
994
|
exportCsv: "CSV",
|
|
995
995
|
exportJson: "JSON",
|
|
996
|
+
exportFailed: "Export failed. Please try again.",
|
|
996
997
|
refresh: "Refresh",
|
|
997
998
|
view: "View",
|
|
998
999
|
tableView: "Table",
|
|
@@ -1024,6 +1025,7 @@ var messages2 = {
|
|
|
1024
1025
|
export: "Exporter",
|
|
1025
1026
|
exportCsv: "CSV",
|
|
1026
1027
|
exportJson: "JSON",
|
|
1028
|
+
exportFailed: "L’exportation a échoué. Veuillez réessayer.",
|
|
1027
1029
|
refresh: "Rafraîchir",
|
|
1028
1030
|
view: "Affichage",
|
|
1029
1031
|
tableView: "Tableau",
|
|
@@ -1586,7 +1588,7 @@ var DataTableRowActions = ({
|
|
|
1586
1588
|
event.stopPropagation();
|
|
1587
1589
|
action.onClick(row);
|
|
1588
1590
|
},
|
|
1589
|
-
variant: action.variant,
|
|
1591
|
+
variant: action.variant ?? "default",
|
|
1590
1592
|
children: [
|
|
1591
1593
|
action.icon,
|
|
1592
1594
|
action.name
|
|
@@ -1641,6 +1643,9 @@ var DataTableToolbar = ({
|
|
|
1641
1643
|
tableAtom
|
|
1642
1644
|
}) => {
|
|
1643
1645
|
const [store, setStore] = useTableAtom(tableAtom);
|
|
1646
|
+
const exportPending = useRef(false);
|
|
1647
|
+
const [exporting, setExporting] = useState(false);
|
|
1648
|
+
const [exportFailed, setExportFailed] = useState(false);
|
|
1644
1649
|
const { features, labels } = store.config;
|
|
1645
1650
|
const model = deriveModel(store);
|
|
1646
1651
|
const selectedRows = getSelectedRows(store, model);
|
|
@@ -1653,6 +1658,27 @@ var DataTableToolbar = ({
|
|
|
1653
1658
|
const update = (next) => changeState(setStore, next);
|
|
1654
1659
|
const visibleBulkActions = bulkActions ? bulkActions.items.filter((action) => !action.visible || action.visible(selectedRows)) : [];
|
|
1655
1660
|
const exportRows = features.export && features.export.scope === "filteredRows" ? model.filteredRows : model.pageRows;
|
|
1661
|
+
const exportFeature = features.export;
|
|
1662
|
+
const exportActions = exportFeature ? exportFeature.actions ?? [] : [];
|
|
1663
|
+
const builtInExport = exportFeature && exportFeature.builtIn !== false;
|
|
1664
|
+
const canExport = builtInExport && exportRows.length > 0 || exportActions.some((action) => !action.disabled);
|
|
1665
|
+
const runExport = async (action) => {
|
|
1666
|
+
if (exportPending.current || action.disabled)
|
|
1667
|
+
return;
|
|
1668
|
+
exportPending.current = true;
|
|
1669
|
+
setExporting(true);
|
|
1670
|
+
setExportFailed(false);
|
|
1671
|
+
try {
|
|
1672
|
+
await action.onExport();
|
|
1673
|
+
} catch (error) {
|
|
1674
|
+
setExportFailed(true);
|
|
1675
|
+
if (exportFeature)
|
|
1676
|
+
exportFeature.onError?.(error, action);
|
|
1677
|
+
} finally {
|
|
1678
|
+
exportPending.current = false;
|
|
1679
|
+
setExporting(false);
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1656
1682
|
return /* @__PURE__ */ jsxs8("div", {
|
|
1657
1683
|
className: "flex flex-col gap-2 pb-4",
|
|
1658
1684
|
children: [
|
|
@@ -1716,7 +1742,7 @@ var DataTableToolbar = ({
|
|
|
1716
1742
|
/* @__PURE__ */ jsx14(MenubarSeparator, {}),
|
|
1717
1743
|
visibleBulkActions.map((action) => /* @__PURE__ */ jsxs8(MenubarItem, {
|
|
1718
1744
|
onClick: () => action.onClick(selectedRows),
|
|
1719
|
-
variant: action.variant,
|
|
1745
|
+
variant: action.variant ?? "default",
|
|
1720
1746
|
children: [
|
|
1721
1747
|
action.icon,
|
|
1722
1748
|
action.name
|
|
@@ -1786,12 +1812,15 @@ var DataTableToolbar = ({
|
|
|
1786
1812
|
children: [
|
|
1787
1813
|
/* @__PURE__ */ jsxs8(MenubarTrigger, {
|
|
1788
1814
|
"aria-label": labels.export,
|
|
1789
|
-
|
|
1815
|
+
"aria-busy": exporting,
|
|
1816
|
+
disabled: exporting || !canExport,
|
|
1790
1817
|
children: [
|
|
1791
|
-
/* @__PURE__ */ jsx14(
|
|
1818
|
+
exporting ? /* @__PURE__ */ jsx14(RefreshCw, {
|
|
1819
|
+
className: "animate-spin"
|
|
1820
|
+
}) : /* @__PURE__ */ jsx14(Download, {}),
|
|
1792
1821
|
/* @__PURE__ */ jsx14("span", {
|
|
1793
1822
|
className: "hidden sm:inline",
|
|
1794
|
-
children: labels.export
|
|
1823
|
+
children: exporting ? labels.loading : labels.export
|
|
1795
1824
|
})
|
|
1796
1825
|
]
|
|
1797
1826
|
}),
|
|
@@ -1803,23 +1832,38 @@ var DataTableToolbar = ({
|
|
|
1803
1832
|
children: labels.export
|
|
1804
1833
|
}),
|
|
1805
1834
|
/* @__PURE__ */ jsx14(MenubarSeparator, {}),
|
|
1806
|
-
/* @__PURE__ */ jsxs8(
|
|
1807
|
-
onClick: () => downloadCsv(model.visibleColumns.map(columnLabel), exportRows.map((row) => model.visibleColumns.map((column) => String(getDataTableExportValue(row, column, store.config.locale) ?? ""))), features.export ? features.export.baseName : "table"),
|
|
1835
|
+
builtInExport ? /* @__PURE__ */ jsxs8(Fragment, {
|
|
1808
1836
|
children: [
|
|
1809
|
-
/* @__PURE__ */
|
|
1810
|
-
|
|
1837
|
+
/* @__PURE__ */ jsxs8(MenubarItem, {
|
|
1838
|
+
disabled: exporting || !exportRows.length,
|
|
1839
|
+
onClick: () => downloadCsv(model.visibleColumns.map(columnLabel), exportRows.map((row) => model.visibleColumns.map((column) => String(getDataTableExportValue(row, column, store.config.locale) ?? ""))), features.export ? features.export.baseName : "table"),
|
|
1840
|
+
children: [
|
|
1841
|
+
/* @__PURE__ */ jsx14(FileText, {}),
|
|
1842
|
+
labels.exportCsv
|
|
1843
|
+
]
|
|
1844
|
+
}),
|
|
1845
|
+
/* @__PURE__ */ jsxs8(MenubarItem, {
|
|
1846
|
+
disabled: exporting || !exportRows.length,
|
|
1847
|
+
onClick: () => downloadJson(exportRows.map((row) => Object.fromEntries(model.visibleColumns.map((column) => [
|
|
1848
|
+
column.id,
|
|
1849
|
+
getDataTableExportValue(row, column, store.config.locale)
|
|
1850
|
+
]))), features.export ? features.export.baseName : "table"),
|
|
1851
|
+
children: [
|
|
1852
|
+
/* @__PURE__ */ jsx14(FileJson, {}),
|
|
1853
|
+
labels.exportJson
|
|
1854
|
+
]
|
|
1855
|
+
})
|
|
1811
1856
|
]
|
|
1812
|
-
}),
|
|
1813
|
-
/* @__PURE__ */
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
]))), features.export ? features.export.baseName : "table"),
|
|
1857
|
+
}) : null,
|
|
1858
|
+
builtInExport && exportActions.length ? /* @__PURE__ */ jsx14(MenubarSeparator, {}) : null,
|
|
1859
|
+
exportActions.map((action) => /* @__PURE__ */ jsxs8(MenubarItem, {
|
|
1860
|
+
disabled: exporting || action.disabled,
|
|
1861
|
+
onClick: () => void runExport(action),
|
|
1818
1862
|
children: [
|
|
1819
|
-
|
|
1820
|
-
|
|
1863
|
+
action.icon,
|
|
1864
|
+
action.label
|
|
1821
1865
|
]
|
|
1822
|
-
})
|
|
1866
|
+
}, action.id))
|
|
1823
1867
|
]
|
|
1824
1868
|
})
|
|
1825
1869
|
})
|
|
@@ -1827,7 +1871,12 @@ var DataTableToolbar = ({
|
|
|
1827
1871
|
}) : null
|
|
1828
1872
|
]
|
|
1829
1873
|
})
|
|
1830
|
-
})
|
|
1874
|
+
}),
|
|
1875
|
+
exportFeature && exportFailed ? /* @__PURE__ */ jsx14("p", {
|
|
1876
|
+
role: "alert",
|
|
1877
|
+
className: "text-destructive text-sm",
|
|
1878
|
+
children: labels.exportFailed ?? dataTableMessages(store.config.locale).exportFailed
|
|
1879
|
+
}) : null
|
|
1831
1880
|
]
|
|
1832
1881
|
});
|
|
1833
1882
|
};
|
|
@@ -2293,7 +2342,7 @@ var GroupActions = ({
|
|
|
2293
2342
|
children: /* @__PURE__ */ jsx14(DropdownMenuGroup, {
|
|
2294
2343
|
children: visible.map((action) => /* @__PURE__ */ jsxs8(DropdownMenuItem, {
|
|
2295
2344
|
onClick: () => action.onClick(groupId),
|
|
2296
|
-
variant: action.variant,
|
|
2345
|
+
variant: action.variant ?? "default",
|
|
2297
2346
|
children: [
|
|
2298
2347
|
action.icon,
|
|
2299
2348
|
" ",
|
|
@@ -2796,23 +2845,21 @@ var HydratedDataTable = ({
|
|
|
2796
2845
|
setPersistedUiState,
|
|
2797
2846
|
...props
|
|
2798
2847
|
}) => {
|
|
2799
|
-
const
|
|
2800
|
-
if (!transientUiAtomRef.current) {
|
|
2848
|
+
const [transientUiAtom] = useState(() => {
|
|
2801
2849
|
const grouping = props.features?.grouping;
|
|
2802
|
-
|
|
2850
|
+
return Atom.make({
|
|
2803
2851
|
...transientUiFromState(DEFAULT_UI_STATE),
|
|
2804
2852
|
grouping: grouping && grouping.initial ? grouping.initial : []
|
|
2805
2853
|
});
|
|
2806
|
-
}
|
|
2807
|
-
const [transientUiState, setTransientUiState] = useAtom(
|
|
2854
|
+
});
|
|
2855
|
+
const [transientUiState, setTransientUiState] = useAtom(transientUiAtom);
|
|
2808
2856
|
const uiState = useMemo(() => ({ ...persistedUiState, ...transientUiState }), [persistedUiState, transientUiState]);
|
|
2809
2857
|
const setUiState = useCallback((state) => {
|
|
2810
2858
|
setPersistedUiState(persistedUiFromState(state));
|
|
2811
2859
|
setTransientUiState(transientUiFromState(state));
|
|
2812
2860
|
}, [setPersistedUiState, setTransientUiState]);
|
|
2813
2861
|
const validatedConfig = resolveConfig(props, (state) => setUiState(state));
|
|
2814
|
-
const
|
|
2815
|
-
if (!atomRef.current) {
|
|
2862
|
+
const [tableAtom] = useState(() => {
|
|
2816
2863
|
const initial = {
|
|
2817
2864
|
rowData: props.rowData,
|
|
2818
2865
|
columnDefs: props.columnDefs,
|
|
@@ -2820,12 +2867,11 @@ var HydratedDataTable = ({
|
|
|
2820
2867
|
state: initialPublicState(props, uiState),
|
|
2821
2868
|
controlledState: props.state
|
|
2822
2869
|
};
|
|
2823
|
-
|
|
2870
|
+
return Atom.make({
|
|
2824
2871
|
...initial,
|
|
2825
2872
|
model: buildDataTableModel(initial)
|
|
2826
2873
|
});
|
|
2827
|
-
}
|
|
2828
|
-
const tableAtom = atomRef.current;
|
|
2874
|
+
});
|
|
2829
2875
|
const setStore = useAtomSet(tableAtom);
|
|
2830
2876
|
useLayoutEffect(() => {
|
|
2831
2877
|
setStore((store) => {
|
|
@@ -2886,20 +2932,19 @@ var HydratedDataTable = ({
|
|
|
2886
2932
|
};
|
|
2887
2933
|
var DataTable = (props) => {
|
|
2888
2934
|
const locale = useKrakstackLocale3(props.locale);
|
|
2889
|
-
const
|
|
2890
|
-
if (!persistedUiAtomRef.current) {
|
|
2935
|
+
const [persistedUiAtom] = useState(() => {
|
|
2891
2936
|
const pathname = globalThis.window?.location.pathname ?? "/";
|
|
2892
2937
|
const columnIds = normalizeDataTableColumns(props.columnDefs).map(({ id }) => id).join(",");
|
|
2893
2938
|
const viewCapability = props.features?.gallery ? "gallery" : "table";
|
|
2894
|
-
|
|
2939
|
+
return Atom.kvs({
|
|
2895
2940
|
mode: "async",
|
|
2896
2941
|
runtime: dataTableStorageRuntime,
|
|
2897
2942
|
key: `data-table:${pathname}:${columnIds}:${viewCapability}:ui`,
|
|
2898
2943
|
schema: DataTablePersistedUiStateSchema,
|
|
2899
2944
|
defaultValue: () => persistedUiFromState(DEFAULT_UI_STATE)
|
|
2900
2945
|
});
|
|
2901
|
-
}
|
|
2902
|
-
const [persistedUiResult, setPersistedUiState] = useAtom(
|
|
2946
|
+
});
|
|
2947
|
+
const [persistedUiResult, setPersistedUiState] = useAtom(persistedUiAtom);
|
|
2903
2948
|
if (!AsyncResult.isSuccess(persistedUiResult) || AsyncResult.isWaiting(persistedUiResult)) {
|
|
2904
2949
|
return /* @__PURE__ */ jsx14("div", {
|
|
2905
2950
|
"aria-busy": "true",
|
|
@@ -3139,7 +3184,7 @@ var DataTableListMenu = ({
|
|
|
3139
3184
|
event.stopPropagation();
|
|
3140
3185
|
action.onClick(item);
|
|
3141
3186
|
},
|
|
3142
|
-
variant: action.variant,
|
|
3187
|
+
variant: action.variant ?? "default",
|
|
3143
3188
|
children: [
|
|
3144
3189
|
action.icon,
|
|
3145
3190
|
action.name
|
|
@@ -22,6 +22,7 @@ export type GoogleMapMessages = {
|
|
|
22
22
|
errorBody: string;
|
|
23
23
|
zoomIn: string;
|
|
24
24
|
zoomOut: string;
|
|
25
|
+
showArea: string;
|
|
25
26
|
};
|
|
26
27
|
export type GoogleMapMessageTranslations = Partial<Record<string, Partial<GoogleMapMessages>>>;
|
|
27
28
|
export type GoogleMapProps = {
|
|
@@ -32,6 +33,8 @@ export type GoogleMapProps = {
|
|
|
32
33
|
radius?: GoogleMapRadiusOptions | undefined;
|
|
33
34
|
interactive?: boolean | undefined;
|
|
34
35
|
zoomControls?: boolean | undefined;
|
|
36
|
+
fitRadius?: boolean | undefined;
|
|
37
|
+
fitPadding?: number | undefined;
|
|
35
38
|
minZoom?: number | undefined;
|
|
36
39
|
maxZoom?: number | undefined;
|
|
37
40
|
className?: string | undefined;
|
|
@@ -55,11 +58,18 @@ type GoogleMapOptions = {
|
|
|
55
58
|
zoomControl: boolean;
|
|
56
59
|
};
|
|
57
60
|
type GoogleMapInstance = {
|
|
61
|
+
fitBounds: (bounds: GoogleMapBounds, padding: number) => void;
|
|
58
62
|
getZoom: () => number | undefined;
|
|
59
63
|
setCenter: (center: GoogleMapPoint) => void;
|
|
60
64
|
setOptions: (options: Partial<GoogleMapOptions>) => void;
|
|
61
65
|
setZoom: (zoom: number) => void;
|
|
62
66
|
};
|
|
67
|
+
type GoogleMapBounds = {
|
|
68
|
+
north: number;
|
|
69
|
+
south: number;
|
|
70
|
+
east: number;
|
|
71
|
+
west: number;
|
|
72
|
+
};
|
|
63
73
|
type GoogleMarkerInstance = {
|
|
64
74
|
setIcon: (icon?: string) => void;
|
|
65
75
|
setMap: (map: GoogleMapInstance | null) => void;
|
|
@@ -67,6 +77,9 @@ type GoogleMarkerInstance = {
|
|
|
67
77
|
};
|
|
68
78
|
type GoogleCircleStyleOptions = Omit<GoogleMapRadiusOptions, "radiusMeters">;
|
|
69
79
|
type GoogleCircleInstance = {
|
|
80
|
+
getBounds: () => {
|
|
81
|
+
toJSON: () => GoogleMapBounds;
|
|
82
|
+
} | undefined;
|
|
70
83
|
setCenter: (center: GoogleMapPoint) => void;
|
|
71
84
|
setMap: (map: GoogleMapInstance | null) => void;
|
|
72
85
|
setOptions: (options: GoogleCircleStyleOptions) => void;
|
|
@@ -96,5 +109,5 @@ export type GoogleMapsApi = {
|
|
|
96
109
|
};
|
|
97
110
|
};
|
|
98
111
|
};
|
|
99
|
-
export declare function GoogleMap({ apiKey, center, zoom, marker, radius, interactive, zoomControls, minZoom, maxZoom, className, messages: messageOverrides, locale: localeOverride, }: GoogleMapProps): import("react").JSX.Element;
|
|
112
|
+
export declare function GoogleMap({ apiKey, center, zoom, marker, radius, interactive, zoomControls, fitRadius, fitPadding, minZoom, maxZoom, className, messages: messageOverrides, locale: localeOverride, }: GoogleMapProps): import("react").JSX.Element;
|
|
100
113
|
export {};
|