openxiangda 1.0.247 → 1.0.249
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 +1 -1
- package/package.json +3 -1
- package/packages/sdk/dist/runtime/index.cjs +33 -14
- package/packages/sdk/dist/runtime/index.cjs.map +1 -1
- package/packages/sdk/dist/runtime/index.mjs +33 -14
- package/packages/sdk/dist/runtime/index.mjs.map +1 -1
- package/packages/sdk/dist/runtime/react.cjs +33 -14
- package/packages/sdk/dist/runtime/react.cjs.map +1 -1
- package/packages/sdk/dist/runtime/react.mjs +33 -14
- package/packages/sdk/dist/runtime/react.mjs.map +1 -1
- package/packages/sdk/source/admin-list/AdminList.tsx +36 -11
- package/packages/sdk/source/admin-list/dataSources.ts +3 -3
package/README.md
CHANGED
|
@@ -135,7 +135,7 @@ React SPA workspaces publish their frontend with `openxiangda runtime deploy`. E
|
|
|
135
135
|
|
|
136
136
|
Environment-managed `release ship`, recovery `release deploy`, and `release promote` accept the same audited Runtime rollback pair. It is forwarded only to `runtime-stage`, never to resource stages or `app-finalize`. Ship freezes the intent in its private journal so production confirmation can inherit it automatically; without the explicit pair, lineage divergence remains blocked.
|
|
137
137
|
|
|
138
|
-
Before publishing the OpenXiangda npm package, run `npm run test:release` once on the final clean version commit.
|
|
138
|
+
Before publishing the OpenXiangda npm package, run `npm run test:release` once on the final clean version commit. For an AdminList-only SDK patch, use the fixed `npm run test:release:sdk-admin-list` profile instead; it runs the AdminList state and response contracts plus the release-evidence guard without exercising unrelated deployment orchestration. Both commands write hash-bound evidence under `.openxiangda/evidence/tests/<HEAD>/release.json`. `npm publish` validates that evidence against the exact Git commit, package version, Node version, and complete passing result, then runs the mainline guard; it does not execute the selected suite a second time. Unknown or cross-module changes should continue to use the full release suite. Any commit, version, runtime, result, or evidence-hash drift remains fail closed.
|
|
139
139
|
|
|
140
140
|
Parallel tasks develop and test in isolated worktrees, but feature worktrees do not publish. After approved commits are merged and pushed, `sdd bundle <release-change> --changes ...` unions their exact structured scope and preserves the source changes' common Git baseline instead of adopting the post-merge `HEAD`. Old imported changes that predate source-base metadata must pass `--source-base-ref <commit>` explicitly. Commit/push the bundle, then run `release publish --change <release-change> --profile <name>` from a clean local main/master whose commit exactly equals the authoritative remote tip. It verifies without rewriting reviewed SDD files, waits for the app lease, freezes one authoritative App capture, executes exact Form/Backend/Runtime staged steps, atomically finalizes the Root App release, and records a resumable local execution journal. Runtime checks use the narrow head endpoint; immutable Git-base artifact hashes are reused across plans.
|
|
141
141
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openxiangda",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.249",
|
|
4
4
|
"description": "OpenXiangda CLI, workspace build tools, runtime SDK, and form components.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"bin": {
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
"test:changed": "npm run check && node scripts/run-test-suite.mjs --changed --evidence",
|
|
73
73
|
"test:contract": "npm run check && node scripts/run-test-suite.mjs --contract --evidence",
|
|
74
74
|
"test:release": "npm run check && node scripts/run-test-suite.mjs --release --evidence",
|
|
75
|
+
"test:release:sdk-admin-list": "npm run check && node scripts/run-test-suite.mjs --release-profile sdk-admin-list --evidence",
|
|
75
76
|
"test:critical": "npm run test:release",
|
|
76
77
|
"test:all": "node scripts/run-test-suite.mjs --all --evidence",
|
|
77
78
|
"test:full": "npm run test:all",
|
|
@@ -91,6 +92,7 @@
|
|
|
91
92
|
"test:resource-cli": "node scripts/resource-cli-smoke.mjs",
|
|
92
93
|
"test:permission-snapshot": "node scripts/permission-snapshot-smoke.mjs",
|
|
93
94
|
"test:permission-role-users": "node scripts/permission-role-users-smoke.mjs",
|
|
95
|
+
"test:sdk-admin-list": "vitest run packages/sdk/src/runtime/react/admin-list/AdminList.state.test.tsx packages/sdk/src/runtime/react/admin-list/AdminList.selection.test.tsx",
|
|
94
96
|
"test:sdk-bundle": "node scripts/sdk-browser-bundle-smoke.mjs",
|
|
95
97
|
"test:sdk-list-response": "vitest run packages/sdk/src/runtime/react/admin-list/dataSources.test.ts packages/sdk/src/components/core/dataManagementApi.test.ts",
|
|
96
98
|
"test:api-contract": "node scripts/openxiangda-api-contract-smoke.mjs",
|
|
@@ -44484,6 +44484,7 @@ function AdminList(props) {
|
|
|
44484
44484
|
const [notificationApi, notificationHolder] = import_antd12.notification.useNotification();
|
|
44485
44485
|
const [modalApi, modalHolder] = import_antd12.Modal.useModal();
|
|
44486
44486
|
const sourceKey = dataSource.key || "anonymous";
|
|
44487
|
+
const listIdentity = JSON.stringify([listKey, sourceKey]);
|
|
44487
44488
|
const [rawPreference, setRawPreference] = (0, import_react21.useState)(null);
|
|
44488
44489
|
const [preference, setPreference] = (0, import_react21.useState)(
|
|
44489
44490
|
() => mergeAdminListPreference({
|
|
@@ -44503,7 +44504,8 @@ function AdminList(props) {
|
|
|
44503
44504
|
const [settingsTab, setSettingsTab] = (0, import_react21.useState)("search");
|
|
44504
44505
|
const [columnSearch, setColumnSearch] = (0, import_react21.useState)("");
|
|
44505
44506
|
const [expanded, setExpanded] = (0, import_react21.useState)(false);
|
|
44506
|
-
const [
|
|
44507
|
+
const [readyIdentity, setReadyIdentity] = (0, import_react21.useState)(null);
|
|
44508
|
+
const ready = readyIdentity === listIdentity;
|
|
44507
44509
|
const [rows, setRows] = (0, import_react21.useState)([]);
|
|
44508
44510
|
const [total, setTotal] = (0, import_react21.useState)(0);
|
|
44509
44511
|
const [allowedColumnKeys, setAllowedColumnKeys] = (0, import_react21.useState)(void 0);
|
|
@@ -44526,9 +44528,12 @@ function AdminList(props) {
|
|
|
44526
44528
|
const [draggedSearchKey, setDraggedSearchKey] = (0, import_react21.useState)("");
|
|
44527
44529
|
const selectedKeysRef = (0, import_react21.useRef)([]);
|
|
44528
44530
|
const dataSourceRef = (0, import_react21.useRef)(dataSource);
|
|
44531
|
+
const listIdentityRef = (0, import_react21.useRef)(listIdentity);
|
|
44532
|
+
const requestVersionRef = (0, import_react21.useRef)(0);
|
|
44529
44533
|
const onQueryChangeRef = (0, import_react21.useRef)(onQueryChange);
|
|
44530
44534
|
const onSelectionChangeRef = (0, import_react21.useRef)(onSelectionChange);
|
|
44531
44535
|
dataSourceRef.current = dataSource;
|
|
44536
|
+
listIdentityRef.current = listIdentity;
|
|
44532
44537
|
onQueryChangeRef.current = onQueryChange;
|
|
44533
44538
|
onSelectionChangeRef.current = onSelectionChange;
|
|
44534
44539
|
const definitionFingerprint = JSON.stringify({
|
|
@@ -44599,10 +44604,19 @@ function AdminList(props) {
|
|
|
44599
44604
|
}, [rowKey, rowSelectable, rows]);
|
|
44600
44605
|
(0, import_react21.useEffect)(() => {
|
|
44601
44606
|
let active = true;
|
|
44602
|
-
|
|
44607
|
+
const initializationVersion = ++requestVersionRef.current;
|
|
44608
|
+
setReadyIdentity(null);
|
|
44609
|
+
setRows([]);
|
|
44610
|
+
setTotal(0);
|
|
44611
|
+
setAllowedColumnKeys(void 0);
|
|
44612
|
+
setHiddenFieldsCount(0);
|
|
44613
|
+
setLoading(false);
|
|
44614
|
+
setError(null);
|
|
44603
44615
|
const load = async () => {
|
|
44604
44616
|
const saved = dataSourceRef.current.preferences ? await dataSourceRef.current.preferences.get(listKey).catch(() => null) : null;
|
|
44605
|
-
if (!active)
|
|
44617
|
+
if (!active || initializationVersion !== requestVersionRef.current || listIdentityRef.current !== listIdentity) {
|
|
44618
|
+
return;
|
|
44619
|
+
}
|
|
44606
44620
|
setRawPreference(saved);
|
|
44607
44621
|
const merged = mergeAdminListPreference({
|
|
44608
44622
|
version: configVersion,
|
|
@@ -44630,7 +44644,7 @@ function AdminList(props) {
|
|
|
44630
44644
|
selectedKeysRef.current = [];
|
|
44631
44645
|
setSelectedKeys([]);
|
|
44632
44646
|
previousFingerprintRef.current = "";
|
|
44633
|
-
|
|
44647
|
+
setReadyIdentity(listIdentity);
|
|
44634
44648
|
};
|
|
44635
44649
|
void load();
|
|
44636
44650
|
return () => {
|
|
@@ -44642,8 +44656,7 @@ function AdminList(props) {
|
|
|
44642
44656
|
defaultVisibleSearchCount,
|
|
44643
44657
|
definitionFingerprint,
|
|
44644
44658
|
form,
|
|
44645
|
-
|
|
44646
|
-
sourceKey
|
|
44659
|
+
listIdentity
|
|
44647
44660
|
]);
|
|
44648
44661
|
(0, import_react21.useEffect)(() => {
|
|
44649
44662
|
if (!allowedColumnKeys) return;
|
|
@@ -44678,28 +44691,34 @@ function AdminList(props) {
|
|
|
44678
44691
|
]);
|
|
44679
44692
|
const loadData = (0, import_react21.useCallback)(async () => {
|
|
44680
44693
|
if (!ready) return;
|
|
44694
|
+
const requestVersion = ++requestVersionRef.current;
|
|
44695
|
+
const requestedIdentity = listIdentity;
|
|
44696
|
+
const requestedDataSource = dataSourceRef.current;
|
|
44697
|
+
const isCurrentRequest = () => requestVersion === requestVersionRef.current && requestedIdentity === listIdentityRef.current;
|
|
44681
44698
|
setLoading(true);
|
|
44682
44699
|
setError(null);
|
|
44683
44700
|
onQueryChangeRef.current?.(query);
|
|
44684
44701
|
try {
|
|
44685
|
-
const result = await
|
|
44702
|
+
const result = await requestedDataSource.query(query);
|
|
44703
|
+
if (!isCurrentRequest()) return;
|
|
44686
44704
|
setRows(result.rows || []);
|
|
44687
44705
|
setTotal(Math.max(0, Number(result.total || 0)));
|
|
44688
44706
|
setAllowedColumnKeys(result.allowedColumnKeys);
|
|
44689
44707
|
setHiddenFieldsCount(Math.max(0, Number(result.hiddenFieldsCount || 0)));
|
|
44690
44708
|
} catch (requestError) {
|
|
44709
|
+
if (!isCurrentRequest()) return;
|
|
44691
44710
|
setRows([]);
|
|
44692
44711
|
setTotal(0);
|
|
44693
44712
|
setError(
|
|
44694
44713
|
requestError instanceof Error ? requestError : new Error(String(requestError || "\u6570\u636E\u52A0\u8F7D\u5931\u8D25"))
|
|
44695
44714
|
);
|
|
44696
44715
|
} finally {
|
|
44697
|
-
setLoading(false);
|
|
44716
|
+
if (isCurrentRequest()) setLoading(false);
|
|
44698
44717
|
}
|
|
44699
|
-
}, [query, ready]);
|
|
44718
|
+
}, [listIdentity, query, ready]);
|
|
44700
44719
|
(0, import_react21.useEffect)(() => {
|
|
44701
44720
|
if (!ready) return;
|
|
44702
|
-
const fingerprint = queryFingerprint(query,
|
|
44721
|
+
const fingerprint = queryFingerprint(query, listIdentity);
|
|
44703
44722
|
if (previousFingerprintRef.current && previousFingerprintRef.current !== fingerprint && selectedKeysRef.current.length) {
|
|
44704
44723
|
clearSelection("\u67E5\u8BE2\u6761\u4EF6\u6216\u6392\u5E8F\u5DF2\u53D8\u5316\uFF0C\u5DF2\u6E05\u7A7A\u8DE8\u9875\u9009\u62E9");
|
|
44705
44724
|
}
|
|
@@ -44710,7 +44729,7 @@ function AdminList(props) {
|
|
|
44710
44729
|
loadData,
|
|
44711
44730
|
query,
|
|
44712
44731
|
ready,
|
|
44713
|
-
|
|
44732
|
+
listIdentity
|
|
44714
44733
|
]);
|
|
44715
44734
|
const visibleSearchFields = (0, import_react21.useMemo)(() => {
|
|
44716
44735
|
const searchMap = new Map(searchFields.map((field) => [field.key, field]));
|
|
@@ -45885,7 +45904,7 @@ function createFormAdminListSource(options) {
|
|
|
45885
45904
|
filterOperators: options.filterOperators || {}
|
|
45886
45905
|
});
|
|
45887
45906
|
return {
|
|
45888
|
-
key: `form:${appType}:${options.formUuid}`,
|
|
45907
|
+
key: `form:${appType}:${options.formUuid}:${options.listKey}`,
|
|
45889
45908
|
preferences: createAdminListPreferenceStore(options.sdk, appType),
|
|
45890
45909
|
async query(query) {
|
|
45891
45910
|
const filters = {
|
|
@@ -45916,7 +45935,7 @@ function createDataViewAdminListSource(options) {
|
|
|
45916
45935
|
filterOperators: options.filterOperators || {}
|
|
45917
45936
|
});
|
|
45918
45937
|
return {
|
|
45919
|
-
key: `data-view:${appType}:${options.dataViewCode}`,
|
|
45938
|
+
key: `data-view:${appType}:${options.dataViewCode}:${options.listKey}`,
|
|
45920
45939
|
preferences: createAdminListPreferenceStore(options.sdk, appType),
|
|
45921
45940
|
async query(query) {
|
|
45922
45941
|
const filters = {
|
|
@@ -45947,7 +45966,7 @@ function createFunctionAdminListSource(options) {
|
|
|
45947
45966
|
functionCode: options.functionCode
|
|
45948
45967
|
});
|
|
45949
45968
|
return {
|
|
45950
|
-
key: `function:${appType}:${options.functionCode}`,
|
|
45969
|
+
key: `function:${appType}:${options.functionCode}:${options.listKey}`,
|
|
45951
45970
|
preferences: createAdminListPreferenceStore(options.sdk, appType),
|
|
45952
45971
|
async query(query) {
|
|
45953
45972
|
const response = await options.sdk.function.invoke(options.functionCode, {
|