cabloy 5.1.189 → 5.1.191
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/.cabloy-version +1 -1
- package/CHANGELOG.md +25 -0
- package/CLAUDE.md +1 -0
- package/README.md +2 -2
- package/package.json +1 -1
- package/repo-docs/.vitepress/config.mjs +1 -0
- package/repo-docs/demo.md +12 -0
- package/repo-docs/index.md +3 -0
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/packages-cli/cli-set-api/toolsIsolate/test.ts +2 -2
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/packages-vona/vona-core/package.json +1 -1
- package/vona/packages-vona/vona-core/src/lib/core/application.ts +5 -6
- package/vona/packages-vona/vona-core/src/lib/utils/util.ts +7 -2
- package/vona/packages-vona/vona-mock/package.json +1 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/service/product.ts +4 -4
- package/vona/src/suite/a-commerce/modules/commerce-catalog/test/productContent.test.ts +10 -3
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/payScene.commerceOrder.ts +5 -3
- package/vona/src/suite/a-home/modules/home-index/src/bean/meta.printTip.ts +1 -1
- package/vona/src/suite/a-home/modules/home-user/test/accountPasswordReset.test.ts +9 -17
- package/vona/src/suite/a-home/modules/home-user/test/accountPasswordSet.test.ts +9 -17
- package/vona/src/suite-vendor/a-auth/modules/a-auth/package.json +1 -1
- package/vona/src/suite-vendor/a-auth/modules/a-auth/src/controller/passport.ts +4 -2
- package/vona/src/suite-vendor/a-auth/modules/a-auth/test/oauthRequestContext.test.ts +123 -146
- package/vona/src/suite-vendor/a-auth/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/a-pay/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentCallback.ts +1 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/package.json +5 -5
- package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-core/src/bean/bean.core.ts +0 -16
- package/vona/src/suite-vendor/a-vona/modules/a-core/src/bean/meta.runtime.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/src/bean/databaseDialect.betterSqlite3.ts +1 -0
- package/vona/src/suite-vendor/a-vona/modules/a-security/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-security/test/origin.test.ts +12 -2
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/packages-zova/zova/package.json +2 -2
- package/zova/src/suite/a-home/modules/home-passport/src/model/passport.ts +2 -7
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/bean/tableCell.actionOperationsRow.tsx +19 -13
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/blockDetails/controller.tsx +11 -0
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/blockToolbarBulk/controller.tsx +7 -4
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/formFieldDetails/controller.tsx +14 -0
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/lib/detailsPermissions.ts +65 -0
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/lib/index.ts +1 -0
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/lib/utils.ts +3 -3
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/types/details.ts +6 -1
- package/zova/src/suite/cabloy-basic/modules/basic-details/test/lib/detailsPermissions.test.ts +125 -0
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/permissions.ts +2 -8
- package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx +2 -1
- package/zova/src/suite-vendor/a-zova/package.json +3 -3
|
@@ -3,169 +3,146 @@ import { after, before, describe, it } from 'node:test';
|
|
|
3
3
|
import { acquireTestLock, app } from 'vona-mock';
|
|
4
4
|
|
|
5
5
|
describe('oauthRequestContext.test.ts', { concurrency: false }, () => {
|
|
6
|
-
|
|
6
|
+
let release: () => void;
|
|
7
7
|
|
|
8
8
|
before(async () => {
|
|
9
|
-
|
|
9
|
+
release = await acquireTestLock('a-security');
|
|
10
10
|
});
|
|
11
11
|
|
|
12
12
|
after(() => {
|
|
13
|
-
|
|
13
|
+
release();
|
|
14
14
|
});
|
|
15
|
+
|
|
15
16
|
it('passes the callback request through an isolated context without rewriting it', async () => {
|
|
16
17
|
await app.bean.executor.mockCtx(async () => {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
instanceName: outerContext.instanceName!,
|
|
53
|
-
req,
|
|
54
|
-
},
|
|
55
|
-
);
|
|
18
|
+
const req = {
|
|
19
|
+
method: 'GET',
|
|
20
|
+
url: '/api/auth/passport/callback?a=1&b=2',
|
|
21
|
+
headers: {
|
|
22
|
+
'host': 'demo.example.test',
|
|
23
|
+
'user-agent': 'oauth-callback-test',
|
|
24
|
+
},
|
|
25
|
+
httpVersionMajor: 1,
|
|
26
|
+
socket: {
|
|
27
|
+
encrypted: true,
|
|
28
|
+
remoteAddress: '192.0.2.10',
|
|
29
|
+
remotePort: 443,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
const originalUrl = req.url;
|
|
33
|
+
const originalHeaders = { ...req.headers };
|
|
34
|
+
const outerContext = app.ctx;
|
|
35
|
+
const result = await app.bean.executor.newCtx(
|
|
36
|
+
async () => {
|
|
37
|
+
return {
|
|
38
|
+
context: app.ctx,
|
|
39
|
+
request: app.ctx.req,
|
|
40
|
+
method: app.ctx.method,
|
|
41
|
+
host: app.ctx.host,
|
|
42
|
+
protocol: app.ctx.protocol,
|
|
43
|
+
secure: app.ctx.secure,
|
|
44
|
+
query: app.ctx.request.query,
|
|
45
|
+
userAgent: app.ctx.get('user-agent'),
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
instanceName: outerContext.instanceName!,
|
|
50
|
+
req,
|
|
51
|
+
},
|
|
52
|
+
);
|
|
56
53
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
} finally {
|
|
69
|
-
app.proxy = proxyPrevious;
|
|
70
|
-
}
|
|
54
|
+
assert.notEqual(result.context, outerContext);
|
|
55
|
+
assert.equal(result.request, req);
|
|
56
|
+
assert.equal(result.method, 'GET');
|
|
57
|
+
assert.equal(result.host, 'demo.example.test');
|
|
58
|
+
assert.equal(result.protocol, 'https');
|
|
59
|
+
assert.equal(result.secure, true);
|
|
60
|
+
assert.deepEqual(result.query, { a: '1', b: '2' });
|
|
61
|
+
assert.equal(result.userAgent, 'oauth-callback-test');
|
|
62
|
+
assert.equal(req.url, originalUrl);
|
|
63
|
+
assert.deepEqual(req.headers, originalHeaders);
|
|
64
|
+
assert.equal(app.ctx, outerContext);
|
|
71
65
|
});
|
|
72
66
|
});
|
|
73
67
|
|
|
74
|
-
it('logs rejected redirects against the
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
remotePort: 443,
|
|
95
|
-
},
|
|
96
|
-
};
|
|
97
|
-
await app.bean.executor.newCtx(
|
|
98
|
-
async () => {
|
|
99
|
-
assert.equal(app.ctx.host, 'edge.example.test');
|
|
100
|
-
assert.equal(app.ctx.protocol, 'https');
|
|
101
|
-
assert.equal(app.util.host, 'canonical.example.test');
|
|
102
|
-
assert.equal(app.util.protocol, 'http');
|
|
68
|
+
it('logs rejected redirects against the effective request origin', async () => {
|
|
69
|
+
const req = {
|
|
70
|
+
method: 'GET',
|
|
71
|
+
url: '/api/auth/passport/callback',
|
|
72
|
+
headers: {
|
|
73
|
+
host: 'edge.example.test',
|
|
74
|
+
},
|
|
75
|
+
httpVersionMajor: 1,
|
|
76
|
+
socket: {
|
|
77
|
+
encrypted: true,
|
|
78
|
+
remoteAddress: '192.0.2.10',
|
|
79
|
+
remotePort: 443,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
await app.bean.executor.mockCtx(
|
|
83
|
+
async () => {
|
|
84
|
+
assert.equal(app.ctx.host, 'edge.example.test');
|
|
85
|
+
assert.equal(app.ctx.protocol, 'https');
|
|
86
|
+
assert.equal(app.util.host, 'edge.example.test');
|
|
87
|
+
assert.equal(app.util.protocol, 'https');
|
|
103
88
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
89
|
+
const service = app.scope('a-auth').service.auth;
|
|
90
|
+
const logger = (service as any).$logger;
|
|
91
|
+
const warnPrevious = logger.warn;
|
|
92
|
+
const warnings: unknown[][] = [];
|
|
93
|
+
logger.warn = (...args: unknown[]) => warnings.push(args);
|
|
94
|
+
try {
|
|
95
|
+
(service as any)._logOauthRedirectRejected(
|
|
96
|
+
{
|
|
97
|
+
id: -1,
|
|
98
|
+
providerName: 'auth-oauth:oauth',
|
|
99
|
+
clientName: 'github',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
authProviderId: -1,
|
|
103
|
+
instanceName: app.ctx.instanceName!,
|
|
104
|
+
locale: app.ctx.locale,
|
|
105
|
+
redirect: 'https://redirect.example.test/oauth/callback',
|
|
106
|
+
},
|
|
107
|
+
'origin_disallowed',
|
|
108
|
+
);
|
|
109
|
+
} finally {
|
|
110
|
+
logger.warn = warnPrevious;
|
|
111
|
+
}
|
|
127
112
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
event: 'auth.oauth_final_redirect_rejected',
|
|
147
|
-
stage: 'redirect_validation',
|
|
148
|
-
outcome: 'rejected',
|
|
149
|
-
reason: 'origin_disallowed',
|
|
150
|
-
requestHost: 'canonical.example.test',
|
|
151
|
-
requestProtocol: 'http',
|
|
152
|
-
serveHost: 'canonical.example.test',
|
|
153
|
-
serveProtocol: 'http',
|
|
154
|
-
proxyEnabled: true,
|
|
155
|
-
redirectHost: 'edge.example.test',
|
|
156
|
-
hostMatches: false,
|
|
157
|
-
},
|
|
158
|
-
);
|
|
113
|
+
assert.equal(warnings.length, 1);
|
|
114
|
+
assert.equal(warnings[0][0], 'OAuth callback final redirect rejected');
|
|
115
|
+
const diagnostic = warnings[0][1] as Record<string, unknown>;
|
|
116
|
+
assert.deepEqual(
|
|
117
|
+
{
|
|
118
|
+
event: diagnostic.event,
|
|
119
|
+
stage: diagnostic.stage,
|
|
120
|
+
outcome: diagnostic.outcome,
|
|
121
|
+
reason: diagnostic.reason,
|
|
122
|
+
requestHost: diagnostic.requestHost,
|
|
123
|
+
requestProtocol: diagnostic.requestProtocol,
|
|
124
|
+
serveHost: diagnostic.serveHost,
|
|
125
|
+
serveProtocol: diagnostic.serveProtocol,
|
|
126
|
+
proxyEnabled: diagnostic.proxyEnabled,
|
|
127
|
+
redirectHost: diagnostic.redirectHost,
|
|
128
|
+
hostMatches: diagnostic.hostMatches,
|
|
159
129
|
},
|
|
160
130
|
{
|
|
161
|
-
|
|
162
|
-
|
|
131
|
+
event: 'auth.oauth_final_redirect_rejected',
|
|
132
|
+
stage: 'redirect_validation',
|
|
133
|
+
outcome: 'rejected',
|
|
134
|
+
reason: 'origin_disallowed',
|
|
135
|
+
requestHost: 'edge.example.test',
|
|
136
|
+
requestProtocol: 'https',
|
|
137
|
+
serveHost: null,
|
|
138
|
+
serveProtocol: null,
|
|
139
|
+
proxyEnabled: false,
|
|
140
|
+
redirectHost: 'redirect.example.test',
|
|
141
|
+
hostMatches: false,
|
|
163
142
|
},
|
|
164
143
|
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
});
|
|
144
|
+
},
|
|
145
|
+
{ req },
|
|
146
|
+
);
|
|
170
147
|
});
|
|
171
148
|
});
|
|
@@ -88,7 +88,7 @@ export class ServicePaymentCallback extends BeanBase {
|
|
|
88
88
|
|
|
89
89
|
private _assertTrustedOrigin() {
|
|
90
90
|
const { protocol, host } = this.app.config.server.serve;
|
|
91
|
-
if (!protocol || !host) {
|
|
91
|
+
if (!this.app.meta.isTest && (!protocol || !host)) {
|
|
92
92
|
this.app.throw(503, 'payment callbacks require configured server serve protocol and host');
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vona-suite-a-pay",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.9",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "",
|
|
6
6
|
"files": [],
|
|
7
7
|
"type": "module",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"vona-module-a-pay": "^5.0.
|
|
10
|
-
"vona-module-pay-mock": "^5.0.
|
|
11
|
-
"vona-module-pay-paypal": "^5.0.
|
|
12
|
-
"vona-module-pay-stripe": "^5.0.
|
|
9
|
+
"vona-module-a-pay": "^5.0.9",
|
|
10
|
+
"vona-module-pay-mock": "^5.0.9",
|
|
11
|
+
"vona-module-pay-paypal": "^5.0.9",
|
|
12
|
+
"vona-module-pay-stripe": "^5.0.9"
|
|
13
13
|
},
|
|
14
14
|
"title": "a-pay"
|
|
15
15
|
}
|
|
@@ -5,23 +5,7 @@ import type { TypeContextFetch } from '../types/fetch.ts';
|
|
|
5
5
|
|
|
6
6
|
@Bean()
|
|
7
7
|
export class BeanCore extends BeanBase {
|
|
8
|
-
get protocol() {
|
|
9
|
-
return this.app.util.protocol;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
get host() {
|
|
13
|
-
return this.app.util.host;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
8
|
get fetch(): TypeContextFetch {
|
|
17
9
|
return this.ctx.state.fetch ?? globalThis.fetch;
|
|
18
10
|
}
|
|
19
|
-
|
|
20
|
-
getAbsoluteUrl(path?: string) {
|
|
21
|
-
return this.app.util.getAbsoluteUrl(path);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
getAbsoluteUrlByApiPath(path: string) {
|
|
25
|
-
return this.app.util.getAbsoluteUrlByApiPath(path);
|
|
26
|
-
}
|
|
27
11
|
}
|
|
@@ -12,8 +12,8 @@ export interface TypeMetaRuntimeResult {
|
|
|
12
12
|
export class MetaRuntime extends BeanBase implements IMetaRuntimeExecute {
|
|
13
13
|
async execute(): Promise<TypeMetaRuntimeResult> {
|
|
14
14
|
return {
|
|
15
|
-
protocol: this.
|
|
16
|
-
host: this.
|
|
15
|
+
protocol: this.app.util.protocol,
|
|
16
|
+
host: this.app.util.host,
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
}
|
package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/src/bean/databaseDialect.betterSqlite3.ts
CHANGED
|
@@ -98,6 +98,7 @@ export class DatabaseDialectBetterSqlite3 extends ServiceDatabaseDialectBase {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
async function sqlite3_afterCreate(conn) {
|
|
101
|
+
conn.pragma('busy_timeout = 5000');
|
|
101
102
|
const pragma: { journal_mode: string }[] = conn.pragma('journal_mode');
|
|
102
103
|
if (pragma[0]?.journal_mode?.toLocaleLowerCase() !== 'wal') {
|
|
103
104
|
conn.pragma('journal_mode = wal');
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
|
-
import { describe, it } from 'node:test';
|
|
3
|
-
import { app } from 'vona-mock';
|
|
2
|
+
import { after, before, describe, it } from 'node:test';
|
|
3
|
+
import { acquireTestLock, app } from 'vona-mock';
|
|
4
4
|
|
|
5
5
|
describe('origin.test.ts', { concurrency: false }, () => {
|
|
6
|
+
let release: () => void;
|
|
7
|
+
|
|
8
|
+
before(async () => {
|
|
9
|
+
release = await acquireTestLock('a-security');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
after(() => {
|
|
13
|
+
release();
|
|
14
|
+
});
|
|
15
|
+
|
|
6
16
|
it('keeps normal CORS separate from exact credential-link authorization', async () => {
|
|
7
17
|
await withWhiteList('*', async () => {
|
|
8
18
|
assert.equal(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zova",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.167",
|
|
4
4
|
"gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
|
|
5
5
|
"description": "A vue3 framework with ioc",
|
|
6
6
|
"keywords": [
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"zova-core": "^5.1.92",
|
|
49
|
-
"zova-suite-a-zova": "^5.1.
|
|
49
|
+
"zova-suite-a-zova": "^5.1.166"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"clean-package": "^2.2.0",
|
|
@@ -10,12 +10,7 @@ import type {
|
|
|
10
10
|
import { combineQueries, isNil } from '@cabloy/utils';
|
|
11
11
|
import { SchemaObject } from 'openapi3-ts/oas31';
|
|
12
12
|
import { $QueryEnsureFresh, $QueryGetFresh, BeanModelBase, Model } from 'zova-module-a-model';
|
|
13
|
-
import {
|
|
14
|
-
IPermissionHintGeneral,
|
|
15
|
-
IResourceFormActionRowNameRecord,
|
|
16
|
-
IResourceTableActionNameRecord,
|
|
17
|
-
TypeOpenapiPermissions,
|
|
18
|
-
} from 'zova-module-a-openapi';
|
|
13
|
+
import { IPermissionHintGeneral, TypeOpenapiPermissions } from 'zova-module-a-openapi';
|
|
19
14
|
import { ApiApiHomeUserPassportloginOauthPath, OpenApiBaseURL } from 'zova-module-home-api';
|
|
20
15
|
import { isRoleSiteAdmitted } from 'zova-module-home-base';
|
|
21
16
|
|
|
@@ -272,7 +267,7 @@ export class ModelPassport extends BeanModelBase {
|
|
|
272
267
|
|
|
273
268
|
public checkPermission(
|
|
274
269
|
permissions: TypeOpenapiPermissions | undefined,
|
|
275
|
-
actionName?:
|
|
270
|
+
actionName?: string,
|
|
276
271
|
permissionHint?: IPermissionHintGeneral,
|
|
277
272
|
currentData?: Record<string, unknown> | readonly Record<string, unknown>[],
|
|
278
273
|
): boolean {
|
package/zova/src/suite/cabloy-basic/modules/basic-details/src/bean/tableCell.actionOperationsRow.tsx
CHANGED
|
@@ -14,7 +14,8 @@ import { VNode } from 'vue';
|
|
|
14
14
|
import { BeanBase } from 'zova';
|
|
15
15
|
import { TableCell } from 'zova-module-a-table';
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { filterDetailsRowActions } from '../lib/detailsPermissions.js';
|
|
18
|
+
import { checkFormScene } from '../lib/utils.js';
|
|
18
19
|
|
|
19
20
|
declare module 'zova-module-a-openapi' {
|
|
20
21
|
export interface IResourceDetailsActionRowRecord {
|
|
@@ -37,16 +38,16 @@ export class TableCellActionOperationsRow extends BeanBase implements ITableCell
|
|
|
37
38
|
const { $celScope, $$table } = renderContext;
|
|
38
39
|
const actions = options.actions;
|
|
39
40
|
if (!actions || actions.length === 0) return false;
|
|
40
|
-
|
|
41
|
+
const $$details = $celScope.$$details!;
|
|
42
|
+
const actionsVisible = actions.filter(action => {
|
|
43
|
+
return checkFormScene($$details.formScene, action.options?.permission);
|
|
44
|
+
});
|
|
41
45
|
const renders: TypeTableCellRenderComponent[] = [];
|
|
42
|
-
for (const action of
|
|
46
|
+
for (const action of actionsVisible) {
|
|
43
47
|
const actionName = action.name;
|
|
44
48
|
const actionRender = action.render;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (!actionRender) throw new Error(`should specify action render: ${actionName}`);
|
|
48
|
-
renders.push(actionRender);
|
|
49
|
-
}
|
|
49
|
+
if (!actionRender) throw new Error(`should specify action render: ${actionName}`);
|
|
50
|
+
renders.push(actionRender);
|
|
50
51
|
}
|
|
51
52
|
await $$table.cellRenderPrepare(renders);
|
|
52
53
|
return renders.length > 0;
|
|
@@ -60,13 +61,18 @@ export class TableCellActionOperationsRow extends BeanBase implements ITableCell
|
|
|
60
61
|
const { $celScope, $$table } = renderContext;
|
|
61
62
|
const actions = options.actions;
|
|
62
63
|
if (!actions || actions.length === 0) return;
|
|
64
|
+
const $$details = $celScope.$$details!;
|
|
65
|
+
const actionsAllowed = filterDetailsRowActions(
|
|
66
|
+
$$details.formScene,
|
|
67
|
+
$$details.checkPermission.bind($$details),
|
|
68
|
+
actions,
|
|
69
|
+
);
|
|
63
70
|
const domActions: VNode[] = [];
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
const options2 = Object.assign({ key: index }, action.options);
|
|
68
|
-
domActions.push($$table.cellRender(action.render!, options2, renderContext));
|
|
71
|
+
actionsAllowed.forEach((action, index) => {
|
|
72
|
+
const actionOptions = Object.assign({ key: index }, action.options);
|
|
73
|
+
domActions.push($$table.cellRender(action.render!, actionOptions, renderContext));
|
|
69
74
|
});
|
|
75
|
+
if (domActions.length === 0) return;
|
|
70
76
|
return <div class={options.class}>{domActions}</div>;
|
|
71
77
|
}
|
|
72
78
|
}
|
package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/blockDetails/controller.tsx
CHANGED
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
} from 'zova-module-a-openapi';
|
|
14
14
|
import { BeanControllerTableBase } from 'zova-module-a-table';
|
|
15
15
|
|
|
16
|
+
import type { TypeDetailsCheckPermission } from '../../types/details.js';
|
|
17
|
+
|
|
16
18
|
declare module 'zova-module-a-openapi' {
|
|
17
19
|
export interface IResourceBlockRecord {
|
|
18
20
|
'basic-details:blockDetails'?: ControllerBlockDetailsProps;
|
|
@@ -26,6 +28,7 @@ export interface ControllerBlockDetailsProps<
|
|
|
26
28
|
formMeta?: IFormMeta;
|
|
27
29
|
schemaRow?: ISchemaObjectExtensionField;
|
|
28
30
|
schemaForm?: ISchemaObjectExtensionField;
|
|
31
|
+
checkPermission?: TypeDetailsCheckPermission;
|
|
29
32
|
getDetailItems?: () => TData[] | undefined;
|
|
30
33
|
setDetailItems?: (detailItems: TData[]) => void;
|
|
31
34
|
}
|
|
@@ -70,6 +73,14 @@ export class ControllerBlockDetails<TData extends {} = {}> extends BeanControlle
|
|
|
70
73
|
return this.$props.schemaForm!;
|
|
71
74
|
}
|
|
72
75
|
|
|
76
|
+
checkPermission(...args: Parameters<TypeDetailsCheckPermission>) {
|
|
77
|
+
const checkPermission = this.$props.checkPermission;
|
|
78
|
+
if (!checkPermission) {
|
|
79
|
+
throw new Error('should provide enclosing Resource permission checker for details');
|
|
80
|
+
}
|
|
81
|
+
return checkPermission(...args);
|
|
82
|
+
}
|
|
83
|
+
|
|
73
84
|
public async setTableRef(tableRef: BeanControllerTableBase<TData> | undefined) {
|
|
74
85
|
this.tableRef = tableRef;
|
|
75
86
|
}
|
|
@@ -9,7 +9,7 @@ import { VNode } from 'vue';
|
|
|
9
9
|
import { BeanControllerBase, Use } from 'zova';
|
|
10
10
|
import { Controller } from 'zova-module-a-bean';
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { filterDetailsBulkActions } from '../../lib/detailsPermissions.js';
|
|
13
13
|
|
|
14
14
|
declare module 'zova-module-a-openapi' {
|
|
15
15
|
export interface IResourceBlockRecord {
|
|
@@ -46,9 +46,12 @@ export class ControllerBlockToolbarBulk extends BeanControllerBase {
|
|
|
46
46
|
const actions = this.$props.actions;
|
|
47
47
|
if (!actions || actions.length === 0) return;
|
|
48
48
|
const domActions: VNode[] = [];
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
const allowedActions = filterDetailsBulkActions(
|
|
50
|
+
$$details.formScene,
|
|
51
|
+
$$details.checkPermission.bind($$details),
|
|
52
|
+
actions,
|
|
53
|
+
);
|
|
54
|
+
allowedActions.forEach((action, index) => {
|
|
52
55
|
const options = Object.assign({ key: index }, action.options);
|
|
53
56
|
const domAction = $jsx.render(action.render!, options, $celScope, this.$$renderContext);
|
|
54
57
|
if (!domAction) return;
|