@stcn52/pro 0.2.0 → 0.2.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/CHANGELOG.md +6 -0
- package/dist/index.cjs +160 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +160 -41
- package/dist/index.js.map +1 -1
- package/dist/styles.css +16 -6
- package/docs/api.md +15 -0
- package/docs/components.md +6 -2
- package/package.json +21 -19
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.1] — 2026-10-09
|
|
11
|
+
|
|
12
|
+
- Table: preserve selections added during asynchronous bulk operations, align sorting entry points, avoid repeated full-row scans, correct pinned action widths and tree loading geometry, and support wrapping cells and accessible inline actions.
|
|
13
|
+
- Workbench: export the full selected set or reject unavailable records, support local column unfreezing, reset empty-board filters, and show accurate totals for unpaginated grouped lists and boards.
|
|
14
|
+
- Async boundaries: isolate attachment sessions by record, stop disabled forms after validation, accumulate batched uncontrolled state updates, and reject obsolete entity select values.
|
|
15
|
+
|
|
10
16
|
- Clear all 13 lint warnings: publish controlled props before layout effects, reset closed overlays without effect cascades, isolate ref-backed event handlers and render composer tools as components; enforce hook checks and a zero-warning verification gate.
|
|
11
17
|
|
|
12
18
|
- Ship editors: validate owned drag sessions, quarter/year boundaries and wizard drafts; wait for real workbench imports/deletes/edits and preserve new selection, parse quoted multiline CSV safely, guard queued callbacks after unmount, and contain mobile canvas cards.
|
package/dist/index.cjs
CHANGED
|
@@ -95,7 +95,10 @@ function useControllableState(options) {
|
|
|
95
95
|
});
|
|
96
96
|
const setValue = React2.useCallback((next) => {
|
|
97
97
|
const resolved = typeof next === "function" ? next(currentRef.current) : next;
|
|
98
|
-
if (!controlledRef.current)
|
|
98
|
+
if (!controlledRef.current) {
|
|
99
|
+
currentRef.current = resolved;
|
|
100
|
+
setUncontrolled(resolved);
|
|
101
|
+
}
|
|
99
102
|
onChangeRef.current?.(resolved);
|
|
100
103
|
}, []);
|
|
101
104
|
return [current, setValue];
|
|
@@ -2332,7 +2335,7 @@ function SelectionBar({
|
|
|
2332
2335
|
"aria-expanded": moreOpen,
|
|
2333
2336
|
onClick: () => setMoreOpen(true),
|
|
2334
2337
|
children: [
|
|
2335
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "
|
|
2338
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more", size: 14 }),
|
|
2336
2339
|
" ",
|
|
2337
2340
|
locale === "zh-CN" ? "\u66F4\u591A" : "More"
|
|
2338
2341
|
]
|
|
@@ -2362,7 +2365,8 @@ function buildBulkCommands({
|
|
|
2362
2365
|
more,
|
|
2363
2366
|
onNotify,
|
|
2364
2367
|
onEditProperties,
|
|
2365
|
-
onClear
|
|
2368
|
+
onClear,
|
|
2369
|
+
onComplete
|
|
2366
2370
|
}) {
|
|
2367
2371
|
const count = keys.length;
|
|
2368
2372
|
const many = count === 1 ? noun.one : noun.many;
|
|
@@ -2370,7 +2374,8 @@ function buildBulkCommands({
|
|
|
2370
2374
|
if (!count) return;
|
|
2371
2375
|
const finish = () => {
|
|
2372
2376
|
onNotify?.(message2);
|
|
2373
|
-
|
|
2377
|
+
if (onComplete) onComplete(keys);
|
|
2378
|
+
else onClear();
|
|
2374
2379
|
};
|
|
2375
2380
|
const result = run();
|
|
2376
2381
|
if (result) return result.then(finish);
|
|
@@ -4075,6 +4080,7 @@ function BulkBar({
|
|
|
4075
4080
|
someSelected,
|
|
4076
4081
|
onToggleAll,
|
|
4077
4082
|
onClear,
|
|
4083
|
+
onComplete,
|
|
4078
4084
|
onEditProperties,
|
|
4079
4085
|
onExportSelection,
|
|
4080
4086
|
onDelete,
|
|
@@ -4106,7 +4112,8 @@ function BulkBar({
|
|
|
4106
4112
|
],
|
|
4107
4113
|
onNotify,
|
|
4108
4114
|
onEditProperties,
|
|
4109
|
-
onClear
|
|
4115
|
+
onClear,
|
|
4116
|
+
onComplete
|
|
4110
4117
|
});
|
|
4111
4118
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4112
4119
|
SelectionBar,
|
|
@@ -4128,6 +4135,7 @@ function BulkBar({
|
|
|
4128
4135
|
|
|
4129
4136
|
// src/components/table/geometry.ts
|
|
4130
4137
|
var LEADING_WIDTH = 44;
|
|
4138
|
+
var COMPACT_ACTIONS_WIDTH = 96;
|
|
4131
4139
|
function widthStyle(width) {
|
|
4132
4140
|
if (width === void 0) return void 0;
|
|
4133
4141
|
return { width: typeof width === "number" ? `${width}px` : width };
|
|
@@ -4162,6 +4170,7 @@ function pinStyle(pin, direction = "ltr") {
|
|
|
4162
4170
|
}
|
|
4163
4171
|
function SkeletonRows({
|
|
4164
4172
|
columns,
|
|
4173
|
+
compact,
|
|
4165
4174
|
rows,
|
|
4166
4175
|
widths,
|
|
4167
4176
|
selectable,
|
|
@@ -4218,7 +4227,16 @@ function SkeletonRows({
|
|
|
4218
4227
|
},
|
|
4219
4228
|
column.id
|
|
4220
4229
|
)),
|
|
4221
|
-
hasRowActions ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4230
|
+
hasRowActions ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4231
|
+
"td",
|
|
4232
|
+
{
|
|
4233
|
+
className: cx(
|
|
4234
|
+
"pro-table__actions-col",
|
|
4235
|
+
pinned && (compact ? pinClass({ side: "right"}, true) : "is-fixed-right-first")
|
|
4236
|
+
),
|
|
4237
|
+
style: pinned && compact ? pinStyle({ side: "right", offset: 0 }, direction) : void 0
|
|
4238
|
+
}
|
|
4239
|
+
) : null,
|
|
4222
4240
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "pro-table__filler" }),
|
|
4223
4241
|
hasHeaderTools ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "pro-table__tool-col" }) : null
|
|
4224
4242
|
] }, `skeleton-${rowIndex}`)) });
|
|
@@ -4241,7 +4259,7 @@ function ColumnMenu({
|
|
|
4241
4259
|
close();
|
|
4242
4260
|
};
|
|
4243
4261
|
const items = [
|
|
4244
|
-
...column.sortable && onSortChange ? [
|
|
4262
|
+
...(column.sortable || column.sorter) && onSortChange ? [
|
|
4245
4263
|
{
|
|
4246
4264
|
id: "sort",
|
|
4247
4265
|
label: "Sort by",
|
|
@@ -4495,10 +4513,10 @@ function TableHead({
|
|
|
4495
4513
|
"aria-label": `Sort by ${typeof column.header === "string" ? column.header : column.id}`,
|
|
4496
4514
|
children: [
|
|
4497
4515
|
column.header,
|
|
4498
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4499
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name:
|
|
4500
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name:
|
|
4501
|
-
] })
|
|
4516
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pro-table__sort-icon", "aria-hidden": "true", children: current ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: current.direction === "asc" ? "angle-up" : "angle-down", size: 9 }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4517
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "angle-up", size: 9 }),
|
|
4518
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "angle-down", size: 9 })
|
|
4519
|
+
] }) })
|
|
4502
4520
|
]
|
|
4503
4521
|
}
|
|
4504
4522
|
) : column.header,
|
|
@@ -4645,17 +4663,22 @@ function nextCell(key, cell, rowCount, colCount) {
|
|
|
4645
4663
|
else return null;
|
|
4646
4664
|
return next;
|
|
4647
4665
|
}
|
|
4648
|
-
function CellCommands({
|
|
4666
|
+
function CellCommands({
|
|
4667
|
+
actions,
|
|
4668
|
+
row,
|
|
4669
|
+
disabled
|
|
4670
|
+
}) {
|
|
4649
4671
|
if (actions.length === 0) return null;
|
|
4650
4672
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pro-table__cell-actions", children: actions.map((action) => /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { label: action.label, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4651
4673
|
"button",
|
|
4652
4674
|
{
|
|
4653
4675
|
type: "button",
|
|
4676
|
+
disabled,
|
|
4654
4677
|
className: "pro-table__cell-action",
|
|
4655
4678
|
"aria-label": action.label,
|
|
4656
4679
|
onClick: (event) => {
|
|
4657
4680
|
event.stopPropagation();
|
|
4658
|
-
action.onSelect(row);
|
|
4681
|
+
if (!disabled) action.onSelect(row);
|
|
4659
4682
|
},
|
|
4660
4683
|
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: action.icon, size: 14 })
|
|
4661
4684
|
}
|
|
@@ -4839,12 +4862,13 @@ function TableRow({
|
|
|
4839
4862
|
{
|
|
4840
4863
|
className: cx(
|
|
4841
4864
|
"pro-table__cell",
|
|
4865
|
+
column.ellipsis === false && "pro-table__cell--wrap",
|
|
4842
4866
|
column.align === "center" && "pro-table__cell--center",
|
|
4843
4867
|
column.align === "right" && "pro-table__cell--right"
|
|
4844
4868
|
),
|
|
4845
4869
|
children: [
|
|
4846
4870
|
/* @__PURE__ */ jsxRuntime.jsx(CellContent, { value: column.render(row, index), ellipsis: column.ellipsis }),
|
|
4847
|
-
column.actions?.length ? /* @__PURE__ */ jsxRuntime.jsx(CellCommands, { actions: column.actions, row }) : null
|
|
4871
|
+
column.actions?.length ? /* @__PURE__ */ jsxRuntime.jsx(CellCommands, { actions: column.actions, row, disabled }) : null
|
|
4848
4872
|
]
|
|
4849
4873
|
}
|
|
4850
4874
|
)
|
|
@@ -4856,7 +4880,11 @@ function TableRow({
|
|
|
4856
4880
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4857
4881
|
"td",
|
|
4858
4882
|
{
|
|
4859
|
-
className: cx(
|
|
4883
|
+
className: cx(
|
|
4884
|
+
"pro-table__actions-col",
|
|
4885
|
+
pinned && (compact ? pinClass({ side: "right"}, true) : "is-fixed-right-first")
|
|
4886
|
+
),
|
|
4887
|
+
style: pinned && compact ? pinStyle({ side: "right", offset: 0 }, direction) : void 0,
|
|
4860
4888
|
onClick: (event) => event.stopPropagation(),
|
|
4861
4889
|
children: compact ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pro-table__cell pro-table__cell--actions", children: rowActions(row) }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pro-table__row-actions", children: rowActions(row) })
|
|
4862
4890
|
}
|
|
@@ -5018,6 +5046,44 @@ function DataTable({
|
|
|
5018
5046
|
const { direction, locale } = useProConfig();
|
|
5019
5047
|
const { leaves: columns, headers } = React2.useMemo(() => tableColumns(suppliedColumns), [suppliedColumns]);
|
|
5020
5048
|
const selectionName = React2.useId();
|
|
5049
|
+
const selectionMounted = React2.useRef(false);
|
|
5050
|
+
React2.useLayoutEffect(() => {
|
|
5051
|
+
selectionMounted.current = true;
|
|
5052
|
+
return () => {
|
|
5053
|
+
selectionMounted.current = false;
|
|
5054
|
+
};
|
|
5055
|
+
}, []);
|
|
5056
|
+
const latestSelection = React2.useRef({
|
|
5057
|
+
selectedKeys,
|
|
5058
|
+
onSelectedKeysChange,
|
|
5059
|
+
suppliedRows,
|
|
5060
|
+
rowKey,
|
|
5061
|
+
getChildren,
|
|
5062
|
+
isRowSelectable,
|
|
5063
|
+
onNotify
|
|
5064
|
+
});
|
|
5065
|
+
React2.useLayoutEffect(() => {
|
|
5066
|
+
latestSelection.current = {
|
|
5067
|
+
selectedKeys,
|
|
5068
|
+
onSelectedKeysChange,
|
|
5069
|
+
suppliedRows,
|
|
5070
|
+
rowKey,
|
|
5071
|
+
getChildren,
|
|
5072
|
+
isRowSelectable,
|
|
5073
|
+
onNotify
|
|
5074
|
+
};
|
|
5075
|
+
});
|
|
5076
|
+
const clearSelection = (completed) => {
|
|
5077
|
+
if (!selectionMounted.current) return;
|
|
5078
|
+
const current = latestSelection.current;
|
|
5079
|
+
const locked = new Set(
|
|
5080
|
+
flattenRecords(tableRecords(current.suppliedRows, current.rowKey, current.getChildren), null).filter(({ row }) => current.isRowSelectable?.(row) === false).map(({ key }) => key)
|
|
5081
|
+
);
|
|
5082
|
+
const processed2 = completed ? new Set(completed) : void 0;
|
|
5083
|
+
current.onSelectedKeysChange?.(
|
|
5084
|
+
current.selectedKeys.filter((key) => locked.has(key) || processed2 !== void 0 && !processed2.has(key))
|
|
5085
|
+
);
|
|
5086
|
+
};
|
|
5021
5087
|
const [scrollTop, setScrollTop] = React2.useState(0);
|
|
5022
5088
|
const [focusedKey, setFocusedKey] = React2.useState(null);
|
|
5023
5089
|
const [headerHeight, setHeaderHeight] = React2.useState(44);
|
|
@@ -5140,7 +5206,7 @@ function DataTable({
|
|
|
5140
5206
|
const columnsCount = columns.length + (selectable ? 1 : 0) + (showIndex ? 1 : 0) + (rowActions ? 1 : 0) + (headerTools ? 1 : 0) + (hasExpansion ? 1 : 0) + 1;
|
|
5141
5207
|
const pinned = columns.some((column) => column.fixed !== void 0);
|
|
5142
5208
|
const leadingWidth = (selectable ? LEADING_WIDTH : 0) + (showIndex ? LEADING_WIDTH : 0) + (hasExpansion ? LEADING_WIDTH : 0);
|
|
5143
|
-
const pins = pinOffsets(columns, leadingWidth, 0);
|
|
5209
|
+
const pins = pinOffsets(columns, leadingWidth, compact && rowActions ? COMPACT_ACTIONS_WIDTH : 0);
|
|
5144
5210
|
const lastLeft = [...columns].reverse().find((column) => column.fixed === "left")?.id;
|
|
5145
5211
|
const firstRight = columns.find((column) => column.fixed === "right")?.id;
|
|
5146
5212
|
const rootRef = React2.useRef(null);
|
|
@@ -5201,7 +5267,9 @@ function DataTable({
|
|
|
5201
5267
|
const rowHeight = suppliedHeight !== void 0 && Number.isFinite(suppliedHeight) && suppliedHeight > 0 ? suppliedHeight : compact ? 36 : 45;
|
|
5202
5268
|
const overscan = suppliedOverscan !== void 0 && Number.isFinite(suppliedOverscan) ? Math.max(0, Math.floor(suppliedOverscan)) : 3;
|
|
5203
5269
|
const viewportHeight = typeof scroll?.y === "number" && Number.isFinite(scroll.y) && scroll.y > 0 ? scroll.y : 300;
|
|
5204
|
-
const windowed = Boolean(
|
|
5270
|
+
const windowed = Boolean(
|
|
5271
|
+
virtual && !groupBy && !expandedRowRender && !columns.some((column) => column.onCell || column.ellipsis === false)
|
|
5272
|
+
);
|
|
5205
5273
|
const start = windowed ? Math.min(
|
|
5206
5274
|
Math.max(0, rows.length - Math.ceil(viewportHeight / rowHeight)),
|
|
5207
5275
|
Math.max(0, Math.floor((scrollTop - (showHeader ? headerHeight : 0)) / rowHeight) - overscan)
|
|
@@ -5288,9 +5356,10 @@ function DataTable({
|
|
|
5288
5356
|
widths: loadingColumns,
|
|
5289
5357
|
selectable,
|
|
5290
5358
|
showIndex,
|
|
5359
|
+
compact,
|
|
5291
5360
|
hasRowActions: Boolean(rowActions),
|
|
5292
5361
|
hasHeaderTools: Boolean(headerTools),
|
|
5293
|
-
hasExpansion
|
|
5362
|
+
hasExpansion,
|
|
5294
5363
|
pinned,
|
|
5295
5364
|
pins,
|
|
5296
5365
|
lastLeft,
|
|
@@ -5327,6 +5396,7 @@ function DataTable({
|
|
|
5327
5396
|
const indexes = Array.from({ length: end - start }, (_, index) => start + index);
|
|
5328
5397
|
const focusedIndex = focusedKey === null ? -1 : visibleRecords.findIndex((record) => record.key === focusedKey);
|
|
5329
5398
|
if (windowed && focusedIndex >= 0 && !indexes.includes(focusedIndex)) indexes.push(focusedIndex);
|
|
5399
|
+
if (windowed && cursor && rows.length > 0 && !indexes.includes(cursorRow)) indexes.push(cursorRow);
|
|
5330
5400
|
indexes.sort((a, b) => a - b);
|
|
5331
5401
|
const spacer = (height, key) => /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: columnsCount, style: { height, padding: 0, border: 0 } }) }, key);
|
|
5332
5402
|
body = /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
|
|
@@ -5374,17 +5444,14 @@ function DataTable({
|
|
|
5374
5444
|
allSelected,
|
|
5375
5445
|
someSelected,
|
|
5376
5446
|
onToggleAll: toggleAll,
|
|
5377
|
-
onClear: () =>
|
|
5378
|
-
|
|
5379
|
-
(key) => flattenRecords(records, null).some(
|
|
5380
|
-
({ row }) => rowKey(row) === key && isRowSelectable?.(row) === false
|
|
5381
|
-
)
|
|
5382
|
-
)
|
|
5383
|
-
),
|
|
5447
|
+
onClear: () => clearSelection(),
|
|
5448
|
+
onComplete: clearSelection,
|
|
5384
5449
|
onEditProperties,
|
|
5385
5450
|
onExportSelection,
|
|
5386
5451
|
onDelete,
|
|
5387
|
-
onNotify
|
|
5452
|
+
onNotify: (message2) => {
|
|
5453
|
+
if (selectionMounted.current) latestSelection.current.onNotify?.(message2);
|
|
5454
|
+
}
|
|
5388
5455
|
}
|
|
5389
5456
|
) : null,
|
|
5390
5457
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -5407,7 +5474,7 @@ function DataTable({
|
|
|
5407
5474
|
showIndex ? /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: LEADING_WIDTH } }) : null,
|
|
5408
5475
|
hasExpansion ? /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: LEADING_WIDTH } }) : null,
|
|
5409
5476
|
columns.map((column) => /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: column.width } }, column.id)),
|
|
5410
|
-
rowActions ? /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: compact ?
|
|
5477
|
+
rowActions ? /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: compact ? COMPACT_ACTIONS_WIDTH : 0 } }) : null,
|
|
5411
5478
|
/* @__PURE__ */ jsxRuntime.jsx("col", {}),
|
|
5412
5479
|
headerTools ? /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: LEADING_WIDTH } }) : null
|
|
5413
5480
|
] }),
|
|
@@ -10464,7 +10531,10 @@ function isPromise(value) {
|
|
|
10464
10531
|
function clamp(pct) {
|
|
10465
10532
|
return Number.isFinite(pct) ? Math.max(0, Math.min(100, Math.round(pct))) : 0;
|
|
10466
10533
|
}
|
|
10467
|
-
function AttachmentUpload({
|
|
10534
|
+
function AttachmentUpload(props) {
|
|
10535
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AttachmentUploadSession, { ...props }, props.entityId);
|
|
10536
|
+
}
|
|
10537
|
+
function AttachmentUploadSession({
|
|
10468
10538
|
files,
|
|
10469
10539
|
label,
|
|
10470
10540
|
maxSizeMb = DEFAULT_MAX_MB,
|
|
@@ -11386,7 +11456,14 @@ function EntityDialog({
|
|
|
11386
11456
|
const fieldValue = (id) => Object.hasOwn(values, id) && typeof values[id] === "string" ? values[id] : "";
|
|
11387
11457
|
const dirty = Object.keys(values).some((key) => values[key] !== baseline[key]);
|
|
11388
11458
|
const errors = Object.fromEntries(
|
|
11389
|
-
[...fields, ...asideFields].
|
|
11459
|
+
[...fields, ...asideFields].flatMap((field) => {
|
|
11460
|
+
const value = fieldValue(field.id);
|
|
11461
|
+
if (field.required && !value.trim())
|
|
11462
|
+
return [[field.id, zh ? `\u8BF7\u586B\u5199${field.label}` : `${field.label} is required`]];
|
|
11463
|
+
if (field.kind === "select" && value && !field.options?.some((option) => option.value === value))
|
|
11464
|
+
return [[field.id, zh ? `\u8BF7\u9009\u62E9\u6709\u6548\u7684${field.label}` : `Choose a valid ${field.label}`]];
|
|
11465
|
+
return [];
|
|
11466
|
+
})
|
|
11390
11467
|
);
|
|
11391
11468
|
const invalid = Object.keys(errors).length > 0;
|
|
11392
11469
|
const idPrefix = React2.useId();
|
|
@@ -13062,7 +13139,7 @@ function AssigneeCell({ field, row, rowKey }) {
|
|
|
13062
13139
|
disabled,
|
|
13063
13140
|
className: "pro-assignee-cell__assign",
|
|
13064
13141
|
"aria-label": field.assignLabel?.(row) ?? `Assign ${rowKey}`,
|
|
13065
|
-
tabIndex: -1,
|
|
13142
|
+
tabIndex: field.onAssign ? 0 : -1,
|
|
13066
13143
|
onClick: (event) => {
|
|
13067
13144
|
event.stopPropagation();
|
|
13068
13145
|
if (field.onAssign) {
|
|
@@ -13255,6 +13332,7 @@ function ListWorkbench({
|
|
|
13255
13332
|
const [deleteError, setDeleteError] = React2.useState(false);
|
|
13256
13333
|
const [sessionIdentity, setSessionIdentity] = React2.useState(identity);
|
|
13257
13334
|
const [hiddenColumns, setHiddenColumns] = React2.useState([]);
|
|
13335
|
+
const [unfrozenColumns, setUnfrozenColumns] = React2.useState([]);
|
|
13258
13336
|
const [columnsOpen, setColumnsOpen] = React2.useState(false);
|
|
13259
13337
|
const [columnAnchor, setColumnAnchor] = React2.useState(null);
|
|
13260
13338
|
const [settingsOpen, setSettingsOpen] = React2.useState(false);
|
|
@@ -13269,6 +13347,12 @@ function ListWorkbench({
|
|
|
13269
13347
|
const editable = Boolean(editFields && entityKind && onEdit);
|
|
13270
13348
|
const createSheet = Boolean(editFields && entityKind && onCreate);
|
|
13271
13349
|
const filteredEmpty = Boolean(view.q || view.rules.length);
|
|
13350
|
+
const [session, setSession] = React2.useState({ identity });
|
|
13351
|
+
if (session.identity !== identity) setSession({ identity });
|
|
13352
|
+
const boardSession = React2.useRef(session);
|
|
13353
|
+
React2.useLayoutEffect(() => {
|
|
13354
|
+
boardSession.current = session;
|
|
13355
|
+
}, [session]);
|
|
13272
13356
|
const latest = React2.useRef({ onImport, onNotify, onSelectionChange, selection, disabled });
|
|
13273
13357
|
React2.useLayoutEffect(() => {
|
|
13274
13358
|
latest.current = { onImport, onNotify, onSelectionChange, selection, disabled };
|
|
@@ -13297,6 +13381,7 @@ function ListWorkbench({
|
|
|
13297
13381
|
setBulkEditOpen(false);
|
|
13298
13382
|
setBulkConfirm(false);
|
|
13299
13383
|
setHiddenColumns([]);
|
|
13384
|
+
setUnfrozenColumns([]);
|
|
13300
13385
|
}
|
|
13301
13386
|
if (disabled && columnsOpen) setColumnsOpen(false);
|
|
13302
13387
|
if (disabled && settingsOpen) setSettingsOpen(false);
|
|
@@ -13362,7 +13447,9 @@ function ListWorkbench({
|
|
|
13362
13447
|
};
|
|
13363
13448
|
}
|
|
13364
13449
|
return column;
|
|
13365
|
-
}).map(
|
|
13450
|
+
}).map(
|
|
13451
|
+
(column) => frozen.includes(column.id) ? { ...column, fixed: "left" } : unfrozenColumns.includes(column.id) ? { ...column, fixed: void 0 } : column
|
|
13452
|
+
);
|
|
13366
13453
|
const groupValue = React2.useMemo(() => {
|
|
13367
13454
|
if (!view.group) return void 0;
|
|
13368
13455
|
return (row) => {
|
|
@@ -13373,7 +13460,15 @@ function ListWorkbench({
|
|
|
13373
13460
|
}, [view.group]);
|
|
13374
13461
|
const exportCsv = (keys = []) => {
|
|
13375
13462
|
if (disabled) return;
|
|
13376
|
-
const
|
|
13463
|
+
const selected = new Set(keys);
|
|
13464
|
+
const source = selected.size > 0 ? rows.filter((row) => selected.has(rowKey(row))) : sorted;
|
|
13465
|
+
if (selected.size > 0 && source.length !== selected.size) {
|
|
13466
|
+
notify(
|
|
13467
|
+
"error",
|
|
13468
|
+
zh ? "\u90E8\u5206\u6240\u9009\u8BB0\u5F55\u672A\u52A0\u8F7D\uFF0C\u8BF7\u52A0\u8F7D\u5B8C\u6574\u6570\u636E\u540E\u91CD\u8BD5\u3002" : "Some selected records are not loaded. Load all selected records and retry."
|
|
13469
|
+
);
|
|
13470
|
+
return;
|
|
13471
|
+
}
|
|
13377
13472
|
try {
|
|
13378
13473
|
if (onExport) download(`${slug}.csv`, onExport(source));
|
|
13379
13474
|
else exportRowsToCsv(slug, source);
|
|
@@ -13656,7 +13751,7 @@ function ListWorkbench({
|
|
|
13656
13751
|
{
|
|
13657
13752
|
title: `No ${noun.many} to show`,
|
|
13658
13753
|
hint: emptyBoardText ?? "Nothing matches the current filters. Clear them to see the full board.",
|
|
13659
|
-
action: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "default", onClick: () => update({ rules: [], page: 1 }), children: "Clear filters" })
|
|
13754
|
+
action: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "default", onClick: () => update({ q: "", rules: [], page: 1 }), children: "Clear filters" })
|
|
13660
13755
|
}
|
|
13661
13756
|
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
13662
13757
|
selection.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -13666,9 +13761,14 @@ function ListWorkbench({
|
|
|
13666
13761
|
count: selection.length,
|
|
13667
13762
|
clearLabel: "Cancel",
|
|
13668
13763
|
onClear: () => onSelectionChange([]),
|
|
13669
|
-
allSelected:
|
|
13670
|
-
someSelected: selection.some((key) =>
|
|
13671
|
-
onToggleAll: () =>
|
|
13764
|
+
allSelected: sorted.length > 0 && sorted.every((row) => selection.includes(rowKey(row))),
|
|
13765
|
+
someSelected: !sorted.every((row) => selection.includes(rowKey(row))) && selection.some((key) => sorted.some((row) => rowKey(row) === key)),
|
|
13766
|
+
onToggleAll: () => {
|
|
13767
|
+
const keys = sorted.map(rowKey);
|
|
13768
|
+
onSelectionChange(
|
|
13769
|
+
keys.every((key) => selection.includes(key)) ? selection.filter((key) => !keys.includes(key)) : [.../* @__PURE__ */ new Set([...selection, ...keys])]
|
|
13770
|
+
);
|
|
13771
|
+
},
|
|
13672
13772
|
...buildBulkCommands({
|
|
13673
13773
|
bulk,
|
|
13674
13774
|
keys: selection,
|
|
@@ -13682,9 +13782,16 @@ function ListWorkbench({
|
|
|
13682
13782
|
onSelect: () => exportCsv(selection)
|
|
13683
13783
|
}
|
|
13684
13784
|
],
|
|
13685
|
-
onNotify: (message2) =>
|
|
13785
|
+
onNotify: (message2) => {
|
|
13786
|
+
if (live.current && boardSession.current === session) notify("success", message2);
|
|
13787
|
+
},
|
|
13686
13788
|
onEditProperties: bulk?.properties ? () => setBulkEditOpen(true) : void 0,
|
|
13687
|
-
onClear: () => onSelectionChange([])
|
|
13789
|
+
onClear: () => onSelectionChange([]),
|
|
13790
|
+
onComplete: (keys) => {
|
|
13791
|
+
if (!live.current || boardSession.current !== session) return;
|
|
13792
|
+
const processed = new Set(keys);
|
|
13793
|
+
latest.current.onSelectionChange(latest.current.selection.filter((key) => !processed.has(key)));
|
|
13794
|
+
}
|
|
13688
13795
|
})
|
|
13689
13796
|
}
|
|
13690
13797
|
) : null,
|
|
@@ -13724,6 +13831,10 @@ function ListWorkbench({
|
|
|
13724
13831
|
onSortChange: sortFields.length ? (sort) => update({ sort }) : void 0,
|
|
13725
13832
|
onColumnCommand: (command) => {
|
|
13726
13833
|
if (command.kind === "freeze") {
|
|
13834
|
+
if (command.fixed === null && columns.find((column) => column.id === command.columnId)?.fixed) {
|
|
13835
|
+
if (onColumnCommand) onColumnCommand(command);
|
|
13836
|
+
else setUnfrozenColumns((current) => [.../* @__PURE__ */ new Set([...current, command.columnId])]);
|
|
13837
|
+
}
|
|
13727
13838
|
update({
|
|
13728
13839
|
frozen: command.fixed === null ? frozen.filter((id) => id !== command.columnId) : [...frozen.filter((id) => id !== command.columnId), command.columnId]
|
|
13729
13840
|
});
|
|
@@ -13785,7 +13896,10 @@ function ListWorkbench({
|
|
|
13785
13896
|
)
|
|
13786
13897
|
}
|
|
13787
13898
|
),
|
|
13788
|
-
/* @__PURE__ */ jsxRuntime.
|
|
13899
|
+
view.group || view.view === "board" && boardView ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pro-row", style: { justifyContent: "space-between" }, children: [
|
|
13900
|
+
footerLeft ?? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pro-text-sm", children: title }),
|
|
13901
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pro-text-sm", children: zh ? `\u5171 ${total} \u6761` : `Total: ${total}` })
|
|
13902
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
13789
13903
|
Pagination,
|
|
13790
13904
|
{
|
|
13791
13905
|
page,
|
|
@@ -13852,6 +13966,7 @@ function ListWorkbench({
|
|
|
13852
13966
|
onSelect: () => {
|
|
13853
13967
|
update({ q: "", rules: [], sort: null, group: null, preview: "auto", page: 1 });
|
|
13854
13968
|
setHiddenColumns([]);
|
|
13969
|
+
setUnfrozenColumns([]);
|
|
13855
13970
|
}
|
|
13856
13971
|
}
|
|
13857
13972
|
]
|
|
@@ -16903,6 +17018,10 @@ function FormRoot({
|
|
|
16903
17018
|
const store = stores.get(instance);
|
|
16904
17019
|
if (!store) throw new Error("Form requires an instance created by useForm");
|
|
16905
17020
|
const config = useProConfig();
|
|
17021
|
+
const latestSubmit = React2.useRef({ disabled: disabled ?? config.disabled, onFinish });
|
|
17022
|
+
React2.useLayoutEffect(() => {
|
|
17023
|
+
latestSubmit.current = { disabled: disabled ?? config.disabled, onFinish };
|
|
17024
|
+
}, [disabled, config.disabled, onFinish]);
|
|
16906
17025
|
const initial = React2.useRef(initialValues);
|
|
16907
17026
|
const submitting = React2.useRef(false);
|
|
16908
17027
|
const generation = React2.useRef(0);
|
|
@@ -16944,9 +17063,9 @@ function FormRoot({
|
|
|
16944
17063
|
}
|
|
16945
17064
|
return;
|
|
16946
17065
|
}
|
|
16947
|
-
if (generation.current !== current) return;
|
|
17066
|
+
if (generation.current !== current || latestSubmit.current.disabled) return;
|
|
16948
17067
|
try {
|
|
16949
|
-
await onFinish?.(values);
|
|
17068
|
+
await latestSubmit.current.onFinish?.(values);
|
|
16950
17069
|
} catch (error) {
|
|
16951
17070
|
if (generation.current !== current) return;
|
|
16952
17071
|
setSubmitError(true);
|