flexdesk 0.13.0 → 0.14.1
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 +72 -0
- package/css/flexdesk.css +99 -0
- package/dist/charts.js +2 -2
- package/dist/{chunk-M2L4XW2U.js → chunk-FBGP5KN5.js} +33 -21
- package/dist/chunk-FBGP5KN5.js.map +7 -0
- package/dist/{chunk-IYMNDPWH.js → chunk-RQM5Z2MU.js} +2 -2
- package/dist/flexdesk.css +99 -0
- package/dist/flow.js +4 -1
- package/dist/flow.js.map +2 -2
- package/dist/host.js +138 -0
- package/dist/host.js.map +3 -3
- package/dist/tiles.js +11 -3
- package/dist/tiles.js.map +2 -2
- package/dist/widgets.js +564 -6
- package/dist/widgets.js.map +3 -3
- package/dist/wm.js +146 -0
- package/dist/wm.js.map +3 -3
- package/package.json +1 -1
- package/src/flow/kit/dom.js +6 -0
- package/src/host/photino_host.js +176 -0
- package/src/host/photino_host.md +98 -0
- package/src/tiles/chart_tiles.js +14 -1
- package/src/tiling/bottom_panel_tabs.js +201 -0
- package/src/ui/components/alert_log.js +274 -0
- package/src/ui/components/alerts_pane.js +294 -0
- package/src/ui/components/data_table.js +32 -14
- package/src/ui/components/notification_history.js +54 -4
- package/src/ui/utils/auto_scrollbars.js +30 -0
- package/dist/chunk-M2L4XW2U.js.map +0 -7
- /package/dist/{chunk-IYMNDPWH.js.map → chunk-RQM5Z2MU.js.map} +0 -0
package/README.md
CHANGED
|
@@ -907,6 +907,20 @@ list.setColumnVisible(3, true);
|
|
|
907
907
|
A column sorted on and then hidden keeps the order; its arrow comes back with
|
|
908
908
|
the column.
|
|
909
909
|
|
|
910
|
+
### DataTable: the CSV button on every table (0.14.1)
|
|
911
|
+
|
|
912
|
+
`showExportButton: true` draws "Download visible rows as CSV" in the pagination
|
|
913
|
+
strip, and now draws the strip for it on a table that fits on one page too (the
|
|
914
|
+
button alone, no page buttons). `exportFilename` — a string, or `(table) =>
|
|
915
|
+
string` — names the file (default `data.csv`). With a `host` that has `dialogs`
|
|
916
|
+
the button opens the native Save dialog, suggesting that name; without one it
|
|
917
|
+
is a browser download.
|
|
918
|
+
|
|
919
|
+
```js
|
|
920
|
+
DataTable.mount(el, { headers, rows, pagination: true, showExportButton: true,
|
|
921
|
+
exportFilename: 'bugs.csv', host });
|
|
922
|
+
```
|
|
923
|
+
|
|
910
924
|
### DataTable: a select mode (0.12.0)
|
|
911
925
|
|
|
912
926
|
A list whose click opens a row can still let people pick many rows: a toggle
|
|
@@ -1671,6 +1685,43 @@ const nc = new NotificationCenter({ eventBus, maxVisible: 3, overflow: 'collapse
|
|
|
1671
1685
|
nc.mount(document.body);
|
|
1672
1686
|
```
|
|
1673
1687
|
|
|
1688
|
+
### Alerts with history: a log, a pane, a tab host and a bell (0.14.0)
|
|
1689
|
+
|
|
1690
|
+
A toast is the moment. The **alert log** keeps what came in until it is
|
|
1691
|
+
dismissed, and four pieces draw it. Each works without the others:
|
|
1692
|
+
|
|
1693
|
+
| Piece | Entry point | Does |
|
|
1694
|
+
|---|---|---|
|
|
1695
|
+
| `createAlertLog({ source, limit })` | `widgets` | Entries `{id, at, level, title, body?, ref?, read}`, newest first; `add`, `receive`, `markRead`, `dismiss`, `unreadCount`, `worstUnread`, `subscribe`, `loadMore` |
|
|
1696
|
+
| `localSource({ read, write })` | `widgets` | Keeps the whole log in one stored value (localStorage, a workspace file) |
|
|
1697
|
+
| `mountAlertsPane(el, { log, onOpen, onBadge, rules?, stillMatches? })` | `widgets` | Level chips with counts, a filter, day groups, relative times, Open / Dismiss / Mark all read / Clear, *Load older* |
|
|
1698
|
+
| `createBottomPanelTabs(el, { panes, remember, store, eventBus })` | `wm` | The `.twm-bp` tab strip: `select`, `setBadge(id, n, level)`, `bottompanel:show {tab}` |
|
|
1699
|
+
| `new NotificationHistory({ alertLog, mountPoint, alertsTab, onOpen })` | `widgets` | The bell shows the log's unread count in the worst level's colour; a click (and "+N more") opens the Alerts tab |
|
|
1700
|
+
|
|
1701
|
+
A **source** is where entries live: `load({offset, limit})` answers
|
|
1702
|
+
`{entries, more?, unread?}`, plus `markRead(ids | null)` and, optionally,
|
|
1703
|
+
`dismiss(ids | null)`. Without `dismiss`, the pane offers no Dismiss or Clear.
|
|
1704
|
+
Levels are `info`, `warning` and `alert`; `warn`, `error` and `danger` are read as
|
|
1705
|
+
those.
|
|
1706
|
+
|
|
1707
|
+
```js
|
|
1708
|
+
const log = createAlertLog({ source: {
|
|
1709
|
+
load: ({ offset, limit }) => api.notifications({ offset, limit }),
|
|
1710
|
+
markRead: (ids) => (ids ? Promise.all(ids.map(api.readNotification)) : api.readAll()),
|
|
1711
|
+
} });
|
|
1712
|
+
const tabs = createBottomPanelTabs(panelEl, { eventBus, panes: [
|
|
1713
|
+
{ id: 'alerts', label: 'Alerts', eager: true,
|
|
1714
|
+
mount: (el, store, api) => mountAlertsPane(el, { log, onOpen: openRef,
|
|
1715
|
+
onBadge: ({ unread, level }) => api.setBadge('alerts', unread, level) }) },
|
|
1716
|
+
] });
|
|
1717
|
+
new NotificationHistory({ notificationCenter: nc, eventBus, alertLog: log, mountPoint: statusBarEl }).mount();
|
|
1718
|
+
```
|
|
1719
|
+
|
|
1720
|
+
An eager pane, and the first one shown, mount inside `createBottomPanelTabs`
|
|
1721
|
+
before it returns. Reach the host through `mount`'s `api` argument, not the
|
|
1722
|
+
variable being assigned. Without `alertLog` and `mountPoint`, `NotificationHistory`
|
|
1723
|
+
is the bell it was.
|
|
1724
|
+
|
|
1674
1725
|
## The host port
|
|
1675
1726
|
|
|
1676
1727
|
FlexDesk never touches `pywebview`, `fetch`, `localStorage` or the filesystem. It
|
|
@@ -1688,6 +1739,22 @@ createHost({
|
|
|
1688
1739
|
|
|
1689
1740
|
`NULL_HOST` is a valid host with nothing behind it.
|
|
1690
1741
|
|
|
1742
|
+
Two adapters ship ready-made. `createPywebviewHost()` speaks to a pywebview
|
|
1743
|
+
window, and `createPhotinoHost()` (0.14.0) to a Photino.NET window over
|
|
1744
|
+
`window.external.sendMessage` / `receiveMessage`:
|
|
1745
|
+
|
|
1746
|
+
```js
|
|
1747
|
+
import { createPhotinoHost } from '@flexdesk/host';
|
|
1748
|
+
|
|
1749
|
+
// In a browser tab this is NULL_HOST. Keep a capability of your own by passing
|
|
1750
|
+
// it in, or leave one out with null.
|
|
1751
|
+
const host = createPhotinoHost({ state: myServerState, onEvent: (name, value) => {} });
|
|
1752
|
+
```
|
|
1753
|
+
|
|
1754
|
+
Its `window.chrome()` answers `'native'`, `dialogs.saveFile` falls back to a
|
|
1755
|
+
Blob download when the window refuses, and the messages the C# side has to
|
|
1756
|
+
answer are in [`src/host/photino_host.md`](src/host/photino_host.md).
|
|
1757
|
+
|
|
1691
1758
|
## Peer dependencies
|
|
1692
1759
|
|
|
1693
1760
|
`@flexdesk/charts` needs Plotly (4.4 MB). `@flexdesk/editor` needs Monaco (14 MB).
|
|
@@ -1763,6 +1830,11 @@ still drawing. A pie takes `{labels, values}`, a histogram `{values}`. The confi
|
|
|
1763
1830
|
`buildOverlayShapes` gained `verticalLines: [{x, label?, color?, lineStyle?}]` for
|
|
1764
1831
|
the same marker outside a tile.
|
|
1765
1832
|
|
|
1833
|
+
A chart tile's **Download PNG** (0.14.1) goes through the grid's `host`
|
|
1834
|
+
(`new TileGrid({ host })`): with `dialogs`, the native Save dialog — a save
|
|
1835
|
+
toasts where the file went, a cancel says nothing — and with no host, or a
|
|
1836
|
+
`saveFile` that answers null, the browser download it always was.
|
|
1837
|
+
|
|
1766
1838
|
## Styling
|
|
1767
1839
|
|
|
1768
1840
|
Three stylesheets, and that is the whole CSS contract:
|
package/css/flexdesk.css
CHANGED
|
@@ -394,6 +394,12 @@
|
|
|
394
394
|
padding: 0 3px;
|
|
395
395
|
line-height: 1;
|
|
396
396
|
}
|
|
397
|
+
/* On an alert log (STORY-0020): the worst unread level's colour, and the bell
|
|
398
|
+
* itself brighter while anything is unread. */
|
|
399
|
+
.twm-notification-history__badge--info { background: var(--color-info); }
|
|
400
|
+
.twm-notification-history__badge--warning { background: var(--color-warning); color: #1e1e1e; }
|
|
401
|
+
.twm-notification-history__badge--alert { background: var(--color-danger); }
|
|
402
|
+
.twm-notification-history__trigger--unread { color: var(--text-bright); }
|
|
397
403
|
.twm-notification-history__panel {
|
|
398
404
|
position: fixed;
|
|
399
405
|
z-index: 9999;
|
|
@@ -7737,6 +7743,28 @@ tr:hover .twm-row-action { opacity: 1; }
|
|
|
7737
7743
|
color: var(--text-bright);
|
|
7738
7744
|
border-bottom-color: #fff;
|
|
7739
7745
|
}
|
|
7746
|
+
/* A tab's count (createBottomPanelTabs' setBadge): Alerts' unread in the
|
|
7747
|
+
* worst unread level's colour, a Changes count in the neutral one. */
|
|
7748
|
+
.twm-bp__badge {
|
|
7749
|
+
display: inline-flex;
|
|
7750
|
+
align-items: center;
|
|
7751
|
+
justify-content: center;
|
|
7752
|
+
min-width: 16px;
|
|
7753
|
+
height: 16px;
|
|
7754
|
+
margin-left: 6px;
|
|
7755
|
+
padding: 0 4px;
|
|
7756
|
+
box-sizing: border-box;
|
|
7757
|
+
border-radius: 8px;
|
|
7758
|
+
background: var(--accent);
|
|
7759
|
+
color: #fff;
|
|
7760
|
+
font-size: 10.5px;
|
|
7761
|
+
line-height: 16px;
|
|
7762
|
+
text-transform: none;
|
|
7763
|
+
}
|
|
7764
|
+
.twm-bp__badge[hidden] { display: none; }
|
|
7765
|
+
.twm-bp__badge--info { background: color-mix(in srgb, var(--color-info) 35%, var(--surface-0)); }
|
|
7766
|
+
.twm-bp__badge--warning { background: color-mix(in srgb, var(--color-warning) 35%, var(--surface-0)); }
|
|
7767
|
+
.twm-bp__badge--alert { background: color-mix(in srgb, var(--color-danger) 45%, var(--surface-0)); }
|
|
7740
7768
|
.twm-bp__body {
|
|
7741
7769
|
flex: 1 1 auto;
|
|
7742
7770
|
min-height: 0;
|
|
@@ -7782,6 +7810,77 @@ tr:hover .twm-row-action { opacity: 1; }
|
|
|
7782
7810
|
.twm-bp-log__row--error .twm-bp-log__level,
|
|
7783
7811
|
.twm-bp-log__row--error .twm-bp-log__msg { color: var(--color-danger); }
|
|
7784
7812
|
.twm-bp-log__msg { color: var(--text-body); white-space: pre-wrap; word-break: break-word; }
|
|
7813
|
+
|
|
7814
|
+
/* ── The Alerts pane (alerts_pane.js, STORY-0019) ─────────────────────────
|
|
7815
|
+
* bugdesk's Alerts tab, on tokens: rules on the left when the embedder has
|
|
7816
|
+
* them, the log on the right, newest first, grouped by day. */
|
|
7817
|
+
.twm-alerts { display: flex; height: 100%; min-height: 0; font-size: var(--font-size-xs); color: var(--text-body); }
|
|
7818
|
+
/* In the bottom panel the pane fills the body, so the log scrolls and the
|
|
7819
|
+
* status line sits at the foot. Only a pane holding the Alerts pane: other
|
|
7820
|
+
* panes keep their padding and their own height. */
|
|
7821
|
+
.twm-bp-pane:has(> .twm-alerts) { height: 100%; padding: 0; box-sizing: border-box; }
|
|
7822
|
+
.twm-alerts .material-symbols-outlined { font-size: 15px; }
|
|
7823
|
+
.twm-alerts__spacer { flex: 1 1 auto; }
|
|
7824
|
+
.twm-alerts__rules { flex: 0 0 280px; display: flex; flex-direction: column; min-width: 0; border-right: 1px solid var(--border-subtle); }
|
|
7825
|
+
.twm-alerts__head, .twm-alerts__bar { flex: none; display: flex; align-items: center; gap: 8px; min-height: 34px; padding: 0 12px; border-bottom: 1px solid var(--border-subtle); }
|
|
7826
|
+
.twm-alerts__bar { flex-wrap: wrap; }
|
|
7827
|
+
.twm-alerts__caps { color: var(--text-muted); font-size: 10.5px; letter-spacing: .08em; }
|
|
7828
|
+
.twm-alerts__link { padding: 0; border: 0; background: none; color: var(--accent-bright); font: inherit; cursor: pointer; }
|
|
7829
|
+
.twm-alerts__link:hover { text-decoration: underline; }
|
|
7830
|
+
.twm-alerts__rulelist { flex: 1 1 auto; overflow-y: auto; padding: 4px 0; }
|
|
7831
|
+
.twm-alerts__rulebtn { width: 100%; display: flex; align-items: center; gap: 10px; height: 30px; padding: 0 12px; border: 0; background: none; color: var(--text-body); font: inherit; cursor: pointer; }
|
|
7832
|
+
.twm-alerts__rulebtn:hover { background: var(--state-hover); }
|
|
7833
|
+
.twm-alerts__rulebtn--on { background: var(--state-selected); box-shadow: inset 2px 0 0 var(--accent-bright); }
|
|
7834
|
+
.twm-alerts__rulebtn--off { color: var(--text-dim); }
|
|
7835
|
+
.twm-alerts__dot { flex: none; width: 8px; height: 8px; border-radius: 50%; }
|
|
7836
|
+
.twm-alerts__dot--alert { background: var(--color-danger); }
|
|
7837
|
+
.twm-alerts__dot--warning { background: var(--color-warning); }
|
|
7838
|
+
.twm-alerts__dot--info { background: var(--color-info); }
|
|
7839
|
+
.twm-alerts__rulename { flex: 1; min-width: 0; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
7840
|
+
.twm-alerts__meta { flex: none; color: var(--text-muted); font-size: 11px; }
|
|
7841
|
+
.twm-alerts__foot { padding: 6px 12px; border-top: 1px solid var(--border-subtle); color: var(--text-muted); font-size: 11px; line-height: 1.4; }
|
|
7842
|
+
.twm-alerts__main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
|
|
7843
|
+
.twm-alerts__chips { display: flex; gap: 4px; }
|
|
7844
|
+
.twm-alerts__chip { height: 24px; padding: 0 10px; border: 1px solid var(--surface-3); border-radius: 12px; background: none; color: var(--text-secondary); font: inherit; cursor: pointer; }
|
|
7845
|
+
.twm-alerts__chip:hover { color: var(--text-bright); }
|
|
7846
|
+
.twm-alerts__count { color: var(--text-muted); }
|
|
7847
|
+
.twm-alerts__chip--on { border-color: var(--accent-bright); background: var(--state-selected); color: var(--text-bright); }
|
|
7848
|
+
.twm-alerts__q { width: 220px; height: 24px; box-sizing: border-box; padding: 0 8px; border: 1px solid var(--surface-3); border-radius: 3px; background: var(--surface-1); color: var(--text-body); font: inherit; }
|
|
7849
|
+
.twm-alerts__q:focus { outline: none; border-color: var(--accent-bright); }
|
|
7850
|
+
.twm-alerts__btn { height: 24px; }
|
|
7851
|
+
.twm-alerts__btn[hidden] { display: none; }
|
|
7852
|
+
.twm-alerts__log { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
|
|
7853
|
+
.twm-alerts__day { padding: 8px 12px 4px 34px; color: var(--text-muted); font-size: 10.5px; letter-spacing: .08em; }
|
|
7854
|
+
.twm-alerts__row { display: flex; align-items: center; gap: 10px; height: 30px; padding: 0 12px; }
|
|
7855
|
+
.twm-alerts__row:hover { background: var(--state-hover); }
|
|
7856
|
+
.twm-alerts__unread { flex: 0 0 7px; height: 7px; border-radius: 50%; }
|
|
7857
|
+
.twm-alerts__row--unread .twm-alerts__unread { background: var(--accent-bright); }
|
|
7858
|
+
.twm-alerts__icon { flex: 0 0 18px; }
|
|
7859
|
+
.twm-alerts__row--info .twm-alerts__icon { color: var(--color-info); }
|
|
7860
|
+
.twm-alerts__row--warning .twm-alerts__icon { color: var(--color-warning); }
|
|
7861
|
+
.twm-alerts__row--alert .twm-alerts__icon { color: var(--color-danger); }
|
|
7862
|
+
.twm-alerts__time { flex: 0 0 78px; color: var(--text-muted); white-space: nowrap; }
|
|
7863
|
+
.twm-alerts__rule { flex: 0 0 170px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-primary); }
|
|
7864
|
+
.twm-alerts__tag { flex: none; display: inline-flex; align-items: center; height: 18px; padding: 0 6px; border-radius: 3px; background: var(--surface-2); color: var(--text-secondary); font-size: 10.5px; }
|
|
7865
|
+
.twm-alerts__tag--none { display: none; }
|
|
7866
|
+
.twm-alerts__ref { flex: 0 0 auto; max-width: 140px; padding: 0; border: 0; background: none; font-family: var(--font-family-mono); font-size: 11.5px; color: var(--accent-bright); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; }
|
|
7867
|
+
button.twm-alerts__ref { cursor: pointer; }
|
|
7868
|
+
button.twm-alerts__ref:hover { text-decoration: underline; }
|
|
7869
|
+
.twm-alerts__ref:empty { display: none; }
|
|
7870
|
+
.twm-alerts__text { flex: 1 1 auto; min-width: 0; display: flex; gap: 8px; overflow: hidden; white-space: nowrap; }
|
|
7871
|
+
.twm-alerts__title { overflow: hidden; text-overflow: ellipsis; color: var(--text-secondary); }
|
|
7872
|
+
.twm-alerts__row--unread .twm-alerts__title { color: var(--text-primary); font-weight: 500; }
|
|
7873
|
+
.twm-alerts__body { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--text-muted); }
|
|
7874
|
+
.twm-alerts__state { flex: 0 0 128px; font-size: 11px; color: var(--text-muted); }
|
|
7875
|
+
.twm-alerts__state--gone { color: var(--text-dim); font-style: italic; }
|
|
7876
|
+
.twm-alerts__acts { flex: 0 0 auto; display: flex; justify-content: flex-end; gap: 2px; }
|
|
7877
|
+
.twm-alerts__icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; border: 0; border-radius: 3px; background: none; color: var(--text-muted); cursor: pointer; }
|
|
7878
|
+
.twm-alerts__icon-btn:hover { background: var(--surface-2); color: var(--text-bright); }
|
|
7879
|
+
.twm-alerts__icon-btn .material-symbols-outlined { font-size: 14px; }
|
|
7880
|
+
.twm-alerts__none { padding: 28px 16px; text-align: center; color: var(--text-muted); }
|
|
7881
|
+
.twm-alerts__more { display: block; margin: 8px auto; height: 24px; }
|
|
7882
|
+
.twm-alerts__status { flex: none; display: flex; align-items: center; height: 26px; padding: 0 12px; border-top: 1px solid var(--border-subtle); color: var(--text-muted); font-size: 11px; }
|
|
7883
|
+
.twm-alerts__status[hidden] { display: none; }
|
|
7785
7884
|
/* Context menu — override main_new.css's .twm-context-menu to the tighter,
|
|
7786
7885
|
* grid-style look (icon | label) with a flat surface-1 background and
|
|
7787
7886
|
* square corners. All callers (sidebars, tile chrome, desktop bar, …)
|
package/dist/charts.js
CHANGED
|
@@ -42,10 +42,10 @@ import {
|
|
|
42
42
|
strideIndices,
|
|
43
43
|
uid,
|
|
44
44
|
updateChart
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-RQM5Z2MU.js";
|
|
46
46
|
import {
|
|
47
47
|
createRafResizeObserver
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-FBGP5KN5.js";
|
|
49
49
|
import {
|
|
50
50
|
ManagedWindow
|
|
51
51
|
} from "./chunk-6JSOVNID.js";
|
|
@@ -683,6 +683,7 @@ var DataTable = class {
|
|
|
683
683
|
onRowContextMenu: null,
|
|
684
684
|
onCellContextMenu: null,
|
|
685
685
|
showExportButton: false,
|
|
686
|
+
exportFilename: null,
|
|
686
687
|
// The host port. TOP LEVEL, deliberately — NOT inside `services`,
|
|
687
688
|
// which most call sites never pass. Supplies the native save
|
|
688
689
|
// dialog for downloadCSV(); absent => Blob fallback.
|
|
@@ -2400,7 +2401,7 @@ var DataTable = class {
|
|
|
2400
2401
|
const displayedRows = isServerSide ? rows.length : Math.min(pageSize, effectiveTotal - offset);
|
|
2401
2402
|
const endRow = Math.min(offset + displayedRows, effectiveTotal);
|
|
2402
2403
|
const totalPages = Math.max(1, Math.ceil(effectiveTotal / pageSize));
|
|
2403
|
-
if (totalPages <= 1 && !isFiltered) return
|
|
2404
|
+
if (totalPages <= 1 && !isFiltered) return this._createExportOnlyStrip();
|
|
2404
2405
|
const currentPage = Math.floor(offset / pageSize) + 1;
|
|
2405
2406
|
const hasPrev = offset > 0;
|
|
2406
2407
|
const hasNext = offset + pageSize < effectiveTotal;
|
|
@@ -2471,15 +2472,33 @@ var DataTable = class {
|
|
|
2471
2472
|
el.appendChild(lastBtn);
|
|
2472
2473
|
el.appendChild(jumpInput);
|
|
2473
2474
|
el.appendChild(jumpBtn);
|
|
2474
|
-
if (this.config.showExportButton)
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2475
|
+
if (this.config.showExportButton) el.appendChild(this._createExportBtn());
|
|
2476
|
+
return el;
|
|
2477
|
+
}
|
|
2478
|
+
/** The export button: downloadCSV() under the configured file name. */
|
|
2479
|
+
_createExportBtn() {
|
|
2480
|
+
const name = this.config.exportFilename;
|
|
2481
|
+
const filename = (typeof name === "function" ? name(this) : name) || "data.csv";
|
|
2482
|
+
return this._createPaginationBtn(
|
|
2483
|
+
"download",
|
|
2484
|
+
"Download visible rows as CSV",
|
|
2485
|
+
false,
|
|
2486
|
+
() => this.downloadCSV(filename)
|
|
2487
|
+
);
|
|
2488
|
+
}
|
|
2489
|
+
/**
|
|
2490
|
+
* The strip on a table with one page: nothing, as always, unless the export
|
|
2491
|
+
* button needs somewhere to be. Then the button alone, with no page
|
|
2492
|
+
* buttons (0.14.1).
|
|
2493
|
+
*/
|
|
2494
|
+
_createExportOnlyStrip() {
|
|
2495
|
+
if (!this.config.showExportButton) return null;
|
|
2496
|
+
const el = document.createElement("div");
|
|
2497
|
+
el.className = "twm-pagination-controls twm-pagination-controls--export-only";
|
|
2498
|
+
el.style.cssText = "display:flex; align-items:center; gap:6px; padding:2px 8px; border-bottom:1px solid #2a2a2a; font-size:11px;";
|
|
2499
|
+
const spacer = document.createElement("div");
|
|
2500
|
+
spacer.style.flex = "1";
|
|
2501
|
+
el.append(spacer, this._createExportBtn());
|
|
2483
2502
|
return el;
|
|
2484
2503
|
}
|
|
2485
2504
|
_createPaginationBtn(icon, tooltip, disabled, onClick, textLabel = null) {
|
|
@@ -4277,8 +4296,8 @@ var DataTable = class {
|
|
|
4277
4296
|
const pn = this._pageNav({ offset, held: drawn, total, hasMore: hasMoreKnown, pageSize });
|
|
4278
4297
|
const { hasPrev, hasNext, page } = pn;
|
|
4279
4298
|
const totalPages = pn.pages;
|
|
4280
|
-
if (known && totalPages <= 1 && !isFiltered && !hasPrev) return
|
|
4281
|
-
if (!known && !hasPrev && !hasNext) return
|
|
4299
|
+
if (known && totalPages <= 1 && !isFiltered && !hasPrev) return this._createExportOnlyStrip();
|
|
4300
|
+
if (!known && !hasPrev && !hasNext) return this._createExportOnlyStrip();
|
|
4282
4301
|
const maxJump = Number.isFinite(c.maxJumpOffset) ? c.maxJumpOffset : null;
|
|
4283
4302
|
const go = (newOffset) => {
|
|
4284
4303
|
if (source) {
|
|
@@ -4372,14 +4391,7 @@ var DataTable = class {
|
|
|
4372
4391
|
}, "Go");
|
|
4373
4392
|
jumpBtn.dataset.pager = "go";
|
|
4374
4393
|
el.append(info, spacer, firstBtn, prevBtn, pageInfo, nextBtn, lastBtn, jumpInput, jumpBtn);
|
|
4375
|
-
if (c.showExportButton)
|
|
4376
|
-
el.appendChild(this._createPaginationBtn(
|
|
4377
|
-
"download",
|
|
4378
|
-
"Download visible rows as CSV",
|
|
4379
|
-
false,
|
|
4380
|
-
() => this.downloadCSV("data.csv")
|
|
4381
|
-
));
|
|
4382
|
-
}
|
|
4394
|
+
if (c.showExportButton) el.appendChild(this._createExportBtn());
|
|
4383
4395
|
return el;
|
|
4384
4396
|
}
|
|
4385
4397
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -6168,4 +6180,4 @@ export {
|
|
|
6168
6180
|
resolvePaging,
|
|
6169
6181
|
DataTable
|
|
6170
6182
|
};
|
|
6171
|
-
//# sourceMappingURL=chunk-
|
|
6183
|
+
//# sourceMappingURL=chunk-FBGP5KN5.js.map
|