com-angel-authorization 1.0.0 → 1.0.2

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.
@@ -24,7 +24,24 @@ __export(react_exports, {
24
24
  Can: () => Can,
25
25
  PermissionProvider: () => PermissionProvider,
26
26
  PermissionStore: () => import_core2.PermissionStore,
27
+ RESOURCE_PRIVATE_OPTIONS: () => import_resources2.RESOURCE_PRIVATE_OPTIONS,
28
+ RESOURCE_STATUS_DISABLED: () => import_resources2.RESOURCE_STATUS_DISABLED,
29
+ RESOURCE_STATUS_ENABLED: () => import_resources2.RESOURCE_STATUS_ENABLED,
30
+ RESOURCE_STATUS_OPTIONS: () => import_resources2.RESOURCE_STATUS_OPTIONS,
31
+ RESOURCE_TYPE_API: () => import_resources2.RESOURCE_TYPE_API,
32
+ ResourceManager: () => ResourceManager,
33
+ appendQueryParam: () => import_resources2.appendQueryParam,
34
+ buildCreateBody: () => import_resources2.buildCreateBody,
35
+ buildUpdateBody: () => import_resources2.buildUpdateBody,
36
+ createAuthorizationResourceApi: () => import_resources2.createAuthorizationResourceApi,
37
+ createDefaultResourceRequest: () => import_resources2.createDefaultResourceRequest,
27
38
  createPermissionStore: () => import_core2.createPermissionStore,
39
+ extractPagination: () => import_resources2.extractPagination,
40
+ extractRecords: () => import_resources2.extractRecords,
41
+ getAppClientId: () => import_snowflake.getAppClientId,
42
+ getDeviceWorkerId: () => import_snowflake.getDeviceWorkerId,
43
+ mapAuthorizationResource: () => import_resources2.mapAuthorizationResource,
44
+ snowyflake: () => import_snowflake.snowyflake,
28
45
  useHasPermission: () => useHasPermission,
29
46
  useHasRole: () => useHasRole,
30
47
  usePermission: () => usePermission
@@ -141,14 +158,479 @@ function Can({
141
158
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: allowed ? children : fallback });
142
159
  }
143
160
 
161
+ // src/react/ResourceManager.tsx
162
+ var import_react2 = require("react");
163
+ var import_resources = require("../resources");
164
+ var import_jsx_runtime2 = require("react/jsx-runtime");
165
+ var PAGE_SIZE_OPTIONS = ["10", "20", "50", "100"];
166
+ var emptyForm = () => ({
167
+ name: "",
168
+ identification: "",
169
+ status: import_resources.RESOURCE_STATUS_ENABLED,
170
+ private: false,
171
+ description: ""
172
+ });
173
+ function ResourceManager({
174
+ api,
175
+ title = "\u6743\u9650\u70B9\u7BA1\u7406",
176
+ pageSize: initialPageSize = "20",
177
+ toolbarExtra
178
+ }) {
179
+ const [records, setRecords] = (0, import_react2.useState)([]);
180
+ const [loading, setLoading] = (0, import_react2.useState)(false);
181
+ const [error, setError] = (0, import_react2.useState)("");
182
+ const [pageSize, setPageSize] = (0, import_react2.useState)(initialPageSize);
183
+ const [pageToken, setPageToken] = (0, import_react2.useState)("");
184
+ const [hasPreviousPage, setHasPreviousPage] = (0, import_react2.useState)(false);
185
+ const [hasNextPage, setHasNextPage] = (0, import_react2.useState)(false);
186
+ const [dialogOpen, setDialogOpen] = (0, import_react2.useState)(false);
187
+ const [editing, setEditing] = (0, import_react2.useState)(null);
188
+ const [form, setForm] = (0, import_react2.useState)(emptyForm);
189
+ const [saving, setSaving] = (0, import_react2.useState)(false);
190
+ const loadList = (0, import_react2.useCallback)(
191
+ async (direction = "current", token = pageToken) => {
192
+ setLoading(true);
193
+ setError("");
194
+ try {
195
+ const result = await api.list({
196
+ pagination: {
197
+ pageToken: token,
198
+ pageSize,
199
+ pageDirection: direction
200
+ }
201
+ });
202
+ setRecords(result.records);
203
+ setPageToken(result.pageToken);
204
+ setHasPreviousPage(result.hasPreviousPage);
205
+ setHasNextPage(result.hasNextPage);
206
+ } catch (err) {
207
+ setError(err instanceof Error ? err.message : "\u52A0\u8F7D\u5931\u8D25");
208
+ } finally {
209
+ setLoading(false);
210
+ }
211
+ },
212
+ [api, pageSize, pageToken]
213
+ );
214
+ (0, import_react2.useEffect)(() => {
215
+ void loadList("current", "");
216
+ }, [api, pageSize]);
217
+ const openCreate = () => {
218
+ setEditing(null);
219
+ setForm(emptyForm());
220
+ setDialogOpen(true);
221
+ };
222
+ const openEdit = (row) => {
223
+ setEditing(row);
224
+ setForm({
225
+ name: row.name,
226
+ identification: row.identification,
227
+ status: row.status,
228
+ private: row.private,
229
+ description: row.description
230
+ });
231
+ setDialogOpen(true);
232
+ };
233
+ const closeDialog = () => {
234
+ if (saving) return;
235
+ setDialogOpen(false);
236
+ };
237
+ const handleSubmit = async (event) => {
238
+ event.preventDefault();
239
+ if (!form.name.trim()) {
240
+ setError("\u8BF7\u586B\u5199\u6743\u9650\u540D\u79F0");
241
+ return;
242
+ }
243
+ if (!form.identification.trim()) {
244
+ setError("\u8BF7\u586B\u5199\u63A5\u53E3\u6807\u8BC6");
245
+ return;
246
+ }
247
+ setSaving(true);
248
+ setError("");
249
+ try {
250
+ if (editing) {
251
+ await api.update(editing.resourceId, form);
252
+ } else {
253
+ await api.create(form);
254
+ }
255
+ setDialogOpen(false);
256
+ await loadList("current", "");
257
+ } catch (err) {
258
+ setError(err instanceof Error ? err.message : "\u4FDD\u5B58\u5931\u8D25");
259
+ } finally {
260
+ setSaving(false);
261
+ }
262
+ };
263
+ const handleDelete = async (row) => {
264
+ if (!window.confirm(`\u786E\u8BA4\u5220\u9664\u6743\u9650\u70B9\u300C${row.name}\u300D\uFF1F`)) return;
265
+ setError("");
266
+ try {
267
+ await api.remove(row.resourceId);
268
+ await loadList("current", "");
269
+ } catch (err) {
270
+ setError(err instanceof Error ? err.message : "\u5220\u9664\u5931\u8D25");
271
+ }
272
+ };
273
+ const statusLabel = (0, import_react2.useMemo)(
274
+ () => Object.fromEntries(import_resources.RESOURCE_STATUS_OPTIONS.map((o) => [o.value, o.label])),
275
+ []
276
+ );
277
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.root, children: [
278
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.toolbar, children: [
279
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: styles.title, children: title }),
280
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.toolbarRight, children: [
281
+ toolbarExtra,
282
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", style: styles.primaryBtn, onClick: openCreate, children: "\u65B0\u589E" })
283
+ ] })
284
+ ] }),
285
+ error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.error, children: error }) : null,
286
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.tableWrap, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { style: styles.table, children: [
287
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
288
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: styles.th, children: "\u6743\u9650\u540D\u79F0" }),
289
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: styles.th, children: "\u63A5\u53E3\u6807\u8BC6" }),
290
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: styles.th, children: "\u63CF\u8FF0" }),
291
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: { ...styles.th, width: 90 }, children: "\u72B6\u6001" }),
292
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: { ...styles.th, width: 140 }, children: "\u64CD\u4F5C" })
293
+ ] }) }),
294
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: loading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan: 5, style: styles.empty, children: "\u52A0\u8F7D\u4E2D\u2026" }) }) : records.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { colSpan: 5, style: styles.empty, children: "\u6682\u65E0\u6570\u636E" }) }) : records.map((row) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
295
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: styles.td, children: row.name }),
296
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { style: styles.code, children: row.identification }) }),
297
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: styles.td, children: row.description || "\u2014" }),
298
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
299
+ "span",
300
+ {
301
+ style: {
302
+ ...styles.badge,
303
+ background: row.status === import_resources.RESOURCE_STATUS_ENABLED ? "#e8f7ef" : "#f4f4f5",
304
+ color: row.status === import_resources.RESOURCE_STATUS_ENABLED ? "#067647" : "#667085"
305
+ },
306
+ children: statusLabel[row.status] ?? row.status
307
+ }
308
+ ) }),
309
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("td", { style: styles.td, children: [
310
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", style: styles.linkBtn, onClick: () => openEdit(row), children: "\u7F16\u8F91" }),
311
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
312
+ "button",
313
+ {
314
+ type: "button",
315
+ style: { ...styles.linkBtn, color: "#d92d20" },
316
+ onClick: () => void handleDelete(row),
317
+ children: "\u5220\u9664"
318
+ }
319
+ )
320
+ ] })
321
+ ] }, row.resourceId)) })
322
+ ] }) }),
323
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.pagination, children: [
324
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: styles.pageSize, children: [
325
+ "\u6BCF\u9875",
326
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
327
+ "select",
328
+ {
329
+ value: pageSize,
330
+ onChange: (e) => {
331
+ setPageToken("");
332
+ setPageSize(e.target.value);
333
+ },
334
+ style: styles.select,
335
+ children: PAGE_SIZE_OPTIONS.map((size) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: size, children: size }, size))
336
+ }
337
+ )
338
+ ] }),
339
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.pageBtns, children: [
340
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
341
+ "button",
342
+ {
343
+ type: "button",
344
+ style: styles.secondaryBtn,
345
+ disabled: !hasPreviousPage || loading,
346
+ onClick: () => void loadList("previous"),
347
+ children: "\u4E0A\u4E00\u9875"
348
+ }
349
+ ),
350
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
351
+ "button",
352
+ {
353
+ type: "button",
354
+ style: styles.secondaryBtn,
355
+ disabled: !hasNextPage || loading,
356
+ onClick: () => void loadList("next"),
357
+ children: "\u4E0B\u4E00\u9875"
358
+ }
359
+ )
360
+ ] })
361
+ ] }),
362
+ dialogOpen ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.mask, onClick: closeDialog, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
363
+ "div",
364
+ {
365
+ style: styles.dialog,
366
+ onClick: (e) => e.stopPropagation(),
367
+ role: "dialog",
368
+ "aria-modal": "true",
369
+ children: [
370
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.dialogHeader, children: [
371
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: styles.dialogTitle, children: editing ? "\u7F16\u8F91\u6743\u9650\u70B9" : "\u65B0\u589E\u6743\u9650\u70B9" }),
372
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", style: styles.iconBtn, onClick: closeDialog, "aria-label": "\u5173\u95ED", children: "\xD7" })
373
+ ] }),
374
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { style: styles.form, onSubmit: (e) => void handleSubmit(e), children: [
375
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: styles.field, children: [
376
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles.label, children: "\u6743\u9650\u540D\u79F0" }),
377
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
378
+ "input",
379
+ {
380
+ style: styles.input,
381
+ value: form.name,
382
+ onChange: (e) => setForm((prev) => ({ ...prev, name: e.target.value })),
383
+ placeholder: "\u8BF7\u8F93\u5165\u6743\u9650\u540D\u79F0",
384
+ required: true
385
+ }
386
+ )
387
+ ] }),
388
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: styles.field, children: [
389
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles.label, children: "\u63A5\u53E3\u6807\u8BC6" }),
390
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
391
+ "input",
392
+ {
393
+ style: styles.input,
394
+ value: form.identification,
395
+ onChange: (e) => setForm((prev) => ({ ...prev, identification: e.target.value })),
396
+ placeholder: "\u5982 user:list",
397
+ required: true
398
+ }
399
+ )
400
+ ] }),
401
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: styles.field, children: [
402
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles.label, children: "\u72B6\u6001" }),
403
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
404
+ "select",
405
+ {
406
+ style: styles.input,
407
+ value: form.status,
408
+ onChange: (e) => setForm((prev) => ({
409
+ ...prev,
410
+ status: Number(e.target.value)
411
+ })),
412
+ children: import_resources.RESOURCE_STATUS_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
413
+ }
414
+ )
415
+ ] }),
416
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: styles.field, children: [
417
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles.label, children: "\u79C1\u6709\u8D44\u6E90" }),
418
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
419
+ "select",
420
+ {
421
+ style: styles.input,
422
+ value: form.private ? "1" : "0",
423
+ onChange: (e) => setForm((prev) => ({ ...prev, private: e.target.value === "1" })),
424
+ children: import_resources.RESOURCE_PRIVATE_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: opt.value ? "1" : "0", children: opt.label }, String(opt.value)))
425
+ }
426
+ )
427
+ ] }),
428
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: styles.field, children: [
429
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles.label, children: "\u63CF\u8FF0" }),
430
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
431
+ "textarea",
432
+ {
433
+ style: { ...styles.input, minHeight: 88, resize: "vertical" },
434
+ value: form.description,
435
+ onChange: (e) => setForm((prev) => ({ ...prev, description: e.target.value })),
436
+ placeholder: "\u8BF7\u8F93\u5165\u63CF\u8FF0"
437
+ }
438
+ )
439
+ ] }),
440
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.dialogFooter, children: [
441
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", style: styles.secondaryBtn, onClick: closeDialog, children: "\u53D6\u6D88" }),
442
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "submit", style: styles.primaryBtn, disabled: saving, children: saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58" })
443
+ ] })
444
+ ] })
445
+ ]
446
+ }
447
+ ) }) : null
448
+ ] });
449
+ }
450
+ var styles = {
451
+ root: {
452
+ display: "flex",
453
+ flexDirection: "column",
454
+ gap: 16,
455
+ padding: 16,
456
+ color: "#101828",
457
+ fontFamily: '"PingFang SC", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, sans-serif'
458
+ },
459
+ toolbar: {
460
+ display: "flex",
461
+ alignItems: "center",
462
+ justifyContent: "space-between",
463
+ gap: 12
464
+ },
465
+ title: { margin: 0, fontSize: 18, fontWeight: 600 },
466
+ toolbarRight: { display: "flex", alignItems: "center", gap: 8 },
467
+ error: {
468
+ padding: "10px 12px",
469
+ borderRadius: 8,
470
+ background: "#fef3f2",
471
+ color: "#b42318",
472
+ fontSize: 13
473
+ },
474
+ tableWrap: {
475
+ overflow: "auto",
476
+ border: "1px solid #eaecf0",
477
+ borderRadius: 10,
478
+ background: "#fff"
479
+ },
480
+ table: { width: "100%", borderCollapse: "collapse", minWidth: 720 },
481
+ th: {
482
+ textAlign: "left",
483
+ padding: "12px 14px",
484
+ fontSize: 13,
485
+ fontWeight: 600,
486
+ color: "#475467",
487
+ background: "#f9fafb",
488
+ borderBottom: "1px solid #eaecf0"
489
+ },
490
+ td: {
491
+ padding: "12px 14px",
492
+ fontSize: 14,
493
+ borderBottom: "1px solid #f2f4f7",
494
+ verticalAlign: "middle"
495
+ },
496
+ empty: {
497
+ padding: 28,
498
+ textAlign: "center",
499
+ color: "#98a2b3",
500
+ fontSize: 14
501
+ },
502
+ code: {
503
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
504
+ fontSize: 13,
505
+ background: "#f2f4f7",
506
+ padding: "2px 6px",
507
+ borderRadius: 4
508
+ },
509
+ badge: {
510
+ display: "inline-block",
511
+ padding: "2px 8px",
512
+ borderRadius: 999,
513
+ fontSize: 12,
514
+ fontWeight: 500
515
+ },
516
+ linkBtn: {
517
+ border: "none",
518
+ background: "transparent",
519
+ color: "#049BAD",
520
+ cursor: "pointer",
521
+ padding: "0 8px 0 0",
522
+ fontSize: 13
523
+ },
524
+ pagination: {
525
+ display: "flex",
526
+ alignItems: "center",
527
+ justifyContent: "space-between",
528
+ gap: 12
529
+ },
530
+ pageSize: { display: "flex", alignItems: "center", gap: 8, fontSize: 13, color: "#475467" },
531
+ pageBtns: { display: "flex", gap: 8 },
532
+ primaryBtn: {
533
+ border: "none",
534
+ background: "#049BAD",
535
+ color: "#fff",
536
+ borderRadius: 8,
537
+ padding: "8px 14px",
538
+ cursor: "pointer",
539
+ fontSize: 14
540
+ },
541
+ secondaryBtn: {
542
+ border: "1px solid #d0d5dd",
543
+ background: "#fff",
544
+ color: "#344054",
545
+ borderRadius: 8,
546
+ padding: "8px 14px",
547
+ cursor: "pointer",
548
+ fontSize: 14
549
+ },
550
+ select: {
551
+ border: "1px solid #d0d5dd",
552
+ borderRadius: 6,
553
+ padding: "4px 8px",
554
+ fontSize: 13
555
+ },
556
+ mask: {
557
+ position: "fixed",
558
+ inset: 0,
559
+ background: "rgba(16, 24, 40, 0.45)",
560
+ display: "flex",
561
+ alignItems: "center",
562
+ justifyContent: "center",
563
+ zIndex: 1e3,
564
+ padding: 16
565
+ },
566
+ dialog: {
567
+ width: "100%",
568
+ maxWidth: 480,
569
+ background: "#fff",
570
+ borderRadius: 12,
571
+ boxShadow: "0 20px 40px rgba(16,24,40,0.18)"
572
+ },
573
+ dialogHeader: {
574
+ display: "flex",
575
+ alignItems: "center",
576
+ justifyContent: "space-between",
577
+ padding: "14px 16px",
578
+ borderBottom: "1px solid #eaecf0"
579
+ },
580
+ dialogTitle: { margin: 0, fontSize: 16, fontWeight: 600 },
581
+ iconBtn: {
582
+ border: "none",
583
+ background: "transparent",
584
+ fontSize: 22,
585
+ lineHeight: 1,
586
+ cursor: "pointer",
587
+ color: "#667085"
588
+ },
589
+ form: { display: "flex", flexDirection: "column", gap: 12, padding: 16 },
590
+ field: { display: "flex", flexDirection: "column", gap: 6 },
591
+ label: { fontSize: 13, color: "#344054", fontWeight: 500 },
592
+ input: {
593
+ border: "1px solid #d0d5dd",
594
+ borderRadius: 8,
595
+ padding: "8px 10px",
596
+ fontSize: 14,
597
+ outline: "none"
598
+ },
599
+ dialogFooter: {
600
+ display: "flex",
601
+ justifyContent: "flex-end",
602
+ gap: 8,
603
+ paddingTop: 4
604
+ }
605
+ };
606
+
144
607
  // src/react/index.ts
145
608
  var import_core2 = require("../core");
609
+ var import_snowflake = require("../utils/snowflake");
610
+ var import_resources2 = require("../resources");
146
611
  // Annotate the CommonJS export names for ESM import in node:
147
612
  0 && (module.exports = {
148
613
  Can,
149
614
  PermissionProvider,
150
615
  PermissionStore,
616
+ RESOURCE_PRIVATE_OPTIONS,
617
+ RESOURCE_STATUS_DISABLED,
618
+ RESOURCE_STATUS_ENABLED,
619
+ RESOURCE_STATUS_OPTIONS,
620
+ RESOURCE_TYPE_API,
621
+ ResourceManager,
622
+ appendQueryParam,
623
+ buildCreateBody,
624
+ buildUpdateBody,
625
+ createAuthorizationResourceApi,
626
+ createDefaultResourceRequest,
151
627
  createPermissionStore,
628
+ extractPagination,
629
+ extractRecords,
630
+ getAppClientId,
631
+ getDeviceWorkerId,
632
+ mapAuthorizationResource,
633
+ snowyflake,
152
634
  useHasPermission,
153
635
  useHasRole,
154
636
  usePermission
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react/index.ts","../../src/react/context.tsx","../../src/react/Can.tsx"],"sourcesContent":["export { PermissionProvider, usePermission, useHasPermission, useHasRole } from './context';\nexport type { PermissionProviderProps, UsePermissionResult } from './context';\n\nexport { Can } from './Can';\nexport type { CanProps } from './Can';\n\nexport type {\n CheckOptions,\n MatchMode,\n PermissionChecker,\n PermissionCode,\n PermissionListener,\n PermissionState,\n RoleCode,\n} from '../core';\n\nexport { PermissionStore, createPermissionStore } from '../core';\n","import {\n createContext,\n createElement,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\nimport {\n createPermissionStore,\n type CheckOptions,\n type PermissionCode,\n type PermissionState,\n type PermissionStore,\n type RoleCode,\n} from '../core';\n\nconst PermissionContext = createContext<PermissionStore | null>(null);\n\nexport interface PermissionProviderProps {\n children: ReactNode;\n /** Pass an existing store to share across trees, or omit to create one. */\n store?: PermissionStore;\n /** Initial state when the provider creates its own store. */\n initialState?: Partial<PermissionState>;\n}\n\nexport function PermissionProvider({\n children,\n store: externalStore,\n initialState,\n}: PermissionProviderProps) {\n const store = useMemo(\n () => externalStore ?? createPermissionStore(initialState),\n // store identity is intentional; initialState only applies on first create\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [externalStore],\n );\n\n return createElement(PermissionContext.Provider, { value: store }, children);\n}\n\nfunction useStore(): PermissionStore {\n const store = useContext(PermissionContext);\n if (!store) {\n throw new Error(\n '[com-angel-authorization/react] usePermission* hooks must be used within <PermissionProvider>.',\n );\n }\n return store;\n}\n\nfunction usePermissionSnapshot(store: PermissionStore): PermissionState {\n const [state, setState] = useState(() => store.getState());\n\n useEffect(() => {\n setState(store.getState());\n return store.subscribe(setState);\n }, [store]);\n\n return state;\n}\n\nexport interface UsePermissionResult {\n permissions: PermissionCode[];\n roles: RoleCode[];\n isSuperAdmin: boolean;\n hasPermission: (codes: PermissionCode | PermissionCode[], options?: CheckOptions) => boolean;\n hasRole: (codes: RoleCode | RoleCode[], options?: CheckOptions) => boolean;\n can: (codes: PermissionCode | PermissionCode[], options?: CheckOptions) => boolean;\n setPermissions: (permissions: PermissionCode[]) => void;\n setRoles: (roles: RoleCode[]) => void;\n setSuperAdmin: (isSuperAdmin: boolean) => void;\n hydrate: (payload: Partial<PermissionState>) => void;\n clear: () => void;\n store: PermissionStore;\n}\n\nexport function usePermission(): UsePermissionResult {\n const store = useStore();\n const state = usePermissionSnapshot(store);\n\n const hasPermission = useCallback(\n (codes: PermissionCode | PermissionCode[], options?: CheckOptions) =>\n store.hasPermission(codes, options),\n [store],\n );\n\n const hasRole = useCallback(\n (codes: RoleCode | RoleCode[], options?: CheckOptions) => store.hasRole(codes, options),\n [store],\n );\n\n const can = useCallback(\n (codes: PermissionCode | PermissionCode[], options?: CheckOptions) => store.can(codes, options),\n [store],\n );\n\n return {\n permissions: state.permissions,\n roles: state.roles,\n isSuperAdmin: Boolean(state.isSuperAdmin),\n hasPermission,\n hasRole,\n can,\n setPermissions: store.setPermissions.bind(store),\n setRoles: store.setRoles.bind(store),\n setSuperAdmin: store.setSuperAdmin.bind(store),\n hydrate: store.hydrate.bind(store),\n clear: store.clear.bind(store),\n store,\n };\n}\n\n/** Returns whether the current user has the given permission(s). */\nexport function useHasPermission(\n codes: PermissionCode | PermissionCode[],\n options?: CheckOptions,\n): boolean {\n const { hasPermission, permissions, isSuperAdmin } = usePermission();\n // re-compute when permission list / super-admin changes\n void permissions;\n void isSuperAdmin;\n return hasPermission(codes, options);\n}\n\n/** Returns whether the current user has the given role(s). */\nexport function useHasRole(\n codes: RoleCode | RoleCode[],\n options?: CheckOptions,\n): boolean {\n const { hasRole, roles, isSuperAdmin } = usePermission();\n void roles;\n void isSuperAdmin;\n return hasRole(codes, options);\n}\n","import type { ReactNode } from 'react';\nimport type { CheckOptions, PermissionCode, RoleCode } from '../core';\nimport { usePermission } from './context';\n\nexport interface CanProps {\n /** Permission codes to check. */\n permission?: PermissionCode | PermissionCode[];\n /** Role codes to check. */\n role?: RoleCode | RoleCode[];\n /**\n * `any` — pass when at least one code matches (default)\n * `all` — pass only when every code matches\n */\n mode?: CheckOptions['mode'];\n /**\n * How permission and role conditions combine when both are provided.\n * Default: `and` (must satisfy both).\n */\n combine?: 'and' | 'or';\n children: ReactNode;\n /** Fallback when access is denied. */\n fallback?: ReactNode;\n}\n\nfunction evaluateAccess(\n hasPermission: (c: PermissionCode | PermissionCode[], o?: CheckOptions) => boolean,\n hasRole: (c: RoleCode | RoleCode[], o?: CheckOptions) => boolean,\n props: Pick<CanProps, 'permission' | 'role' | 'mode' | 'combine'>,\n): boolean {\n const { permission, role, mode, combine = 'and' } = props;\n const options: CheckOptions = { mode };\n\n const hasPermCheck = permission !== undefined;\n const hasRoleCheck = role !== undefined;\n\n if (!hasPermCheck && !hasRoleCheck) return true;\n\n const permOk = hasPermCheck ? hasPermission(permission!, options) : true;\n const roleOk = hasRoleCheck ? hasRole(role!, options) : true;\n\n if (hasPermCheck && hasRoleCheck) {\n return combine === 'or' ? permOk || roleOk : permOk && roleOk;\n }\n\n return hasPermCheck ? permOk : roleOk;\n}\n\n/**\n * Conditionally render children based on permission / role.\n *\n * @example\n * <Can permission=\"user:edit\">\n * <button>Edit</button>\n * </Can>\n *\n * <Can permission={['user:edit', 'user:delete']} mode=\"all\" fallback={null}>\n * <AdminPanel />\n * </Can>\n */\nexport function Can({\n permission,\n role,\n mode,\n combine,\n children,\n fallback = null,\n}: CanProps) {\n const { hasPermission, hasRole } = usePermission();\n const allowed = evaluateAccess(hasPermission, hasRole, {\n permission,\n role,\n mode,\n combine,\n });\n\n return <>{allowed ? children : fallback}</>;\n}\n"],"mappings":"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","names":["import_core"]}
1
+ {"version":3,"sources":["../../src/react/index.ts","../../src/react/context.tsx","../../src/react/Can.tsx","../../src/react/ResourceManager.tsx"],"sourcesContent":["export { PermissionProvider, usePermission, useHasPermission, useHasRole } from './context';\nexport type { PermissionProviderProps, UsePermissionResult } from './context';\n\nexport { Can } from './Can';\nexport type { CanProps } from './Can';\n\nexport { ResourceManager } from './ResourceManager';\nexport type { ResourceManagerProps } from './ResourceManager';\n\nexport type {\n CheckOptions,\n MatchMode,\n PermissionChecker,\n PermissionCode,\n PermissionListener,\n PermissionState,\n RoleCode,\n} from '../core';\n\nexport { PermissionStore, createPermissionStore } from '../core';\n\nexport { getAppClientId, getDeviceWorkerId, snowyflake } from '../utils/snowflake';\n\nexport type {\n AuthorizationResource,\n AuthorizationResourceApi,\n AuthorizationResourceFormValues,\n AuthorizationResourceListResult,\n CreateAuthorizationResourceBody,\n CreateDefaultResourceRequestOptions,\n FetchAuthorizationResourcesParams,\n HttpMethod,\n ListPaginationParams,\n ListPaginationResult,\n PageDirection,\n ResourceHttpRequest,\n ResourceRequestOptions,\n ResourceStatus,\n UpdateAuthorizationResourceBody,\n} from '../resources';\n\nexport {\n RESOURCE_PRIVATE_OPTIONS,\n RESOURCE_STATUS_DISABLED,\n RESOURCE_STATUS_ENABLED,\n RESOURCE_STATUS_OPTIONS,\n RESOURCE_TYPE_API,\n appendQueryParam,\n buildCreateBody,\n buildUpdateBody,\n createAuthorizationResourceApi,\n createDefaultResourceRequest,\n extractPagination,\n extractRecords,\n mapAuthorizationResource,\n} from '../resources';\n","import {\n createContext,\n createElement,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\nimport {\n createPermissionStore,\n type CheckOptions,\n type PermissionCode,\n type PermissionState,\n type PermissionStore,\n type RoleCode,\n} from '../core';\n\nconst PermissionContext = createContext<PermissionStore | null>(null);\n\nexport interface PermissionProviderProps {\n children: ReactNode;\n /** Pass an existing store to share across trees, or omit to create one. */\n store?: PermissionStore;\n /** Initial state when the provider creates its own store. */\n initialState?: Partial<PermissionState>;\n}\n\nexport function PermissionProvider({\n children,\n store: externalStore,\n initialState,\n}: PermissionProviderProps) {\n const store = useMemo(\n () => externalStore ?? createPermissionStore(initialState),\n // store identity is intentional; initialState only applies on first create\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [externalStore],\n );\n\n return createElement(PermissionContext.Provider, { value: store }, children);\n}\n\nfunction useStore(): PermissionStore {\n const store = useContext(PermissionContext);\n if (!store) {\n throw new Error(\n '[com-angel-authorization/react] usePermission* hooks must be used within <PermissionProvider>.',\n );\n }\n return store;\n}\n\nfunction usePermissionSnapshot(store: PermissionStore): PermissionState {\n const [state, setState] = useState(() => store.getState());\n\n useEffect(() => {\n setState(store.getState());\n return store.subscribe(setState);\n }, [store]);\n\n return state;\n}\n\nexport interface UsePermissionResult {\n permissions: PermissionCode[];\n roles: RoleCode[];\n isSuperAdmin: boolean;\n hasPermission: (codes: PermissionCode | PermissionCode[], options?: CheckOptions) => boolean;\n hasRole: (codes: RoleCode | RoleCode[], options?: CheckOptions) => boolean;\n can: (codes: PermissionCode | PermissionCode[], options?: CheckOptions) => boolean;\n setPermissions: (permissions: PermissionCode[]) => void;\n setRoles: (roles: RoleCode[]) => void;\n setSuperAdmin: (isSuperAdmin: boolean) => void;\n hydrate: (payload: Partial<PermissionState>) => void;\n clear: () => void;\n store: PermissionStore;\n}\n\nexport function usePermission(): UsePermissionResult {\n const store = useStore();\n const state = usePermissionSnapshot(store);\n\n const hasPermission = useCallback(\n (codes: PermissionCode | PermissionCode[], options?: CheckOptions) =>\n store.hasPermission(codes, options),\n [store],\n );\n\n const hasRole = useCallback(\n (codes: RoleCode | RoleCode[], options?: CheckOptions) => store.hasRole(codes, options),\n [store],\n );\n\n const can = useCallback(\n (codes: PermissionCode | PermissionCode[], options?: CheckOptions) => store.can(codes, options),\n [store],\n );\n\n return {\n permissions: state.permissions,\n roles: state.roles,\n isSuperAdmin: Boolean(state.isSuperAdmin),\n hasPermission,\n hasRole,\n can,\n setPermissions: store.setPermissions.bind(store),\n setRoles: store.setRoles.bind(store),\n setSuperAdmin: store.setSuperAdmin.bind(store),\n hydrate: store.hydrate.bind(store),\n clear: store.clear.bind(store),\n store,\n };\n}\n\n/** Returns whether the current user has the given permission(s). */\nexport function useHasPermission(\n codes: PermissionCode | PermissionCode[],\n options?: CheckOptions,\n): boolean {\n const { hasPermission, permissions, isSuperAdmin } = usePermission();\n // re-compute when permission list / super-admin changes\n void permissions;\n void isSuperAdmin;\n return hasPermission(codes, options);\n}\n\n/** Returns whether the current user has the given role(s). */\nexport function useHasRole(\n codes: RoleCode | RoleCode[],\n options?: CheckOptions,\n): boolean {\n const { hasRole, roles, isSuperAdmin } = usePermission();\n void roles;\n void isSuperAdmin;\n return hasRole(codes, options);\n}\n","import type { ReactNode } from 'react';\nimport type { CheckOptions, PermissionCode, RoleCode } from '../core';\nimport { usePermission } from './context';\n\nexport interface CanProps {\n /** Permission codes to check. */\n permission?: PermissionCode | PermissionCode[];\n /** Role codes to check. */\n role?: RoleCode | RoleCode[];\n /**\n * `any` — pass when at least one code matches (default)\n * `all` — pass only when every code matches\n */\n mode?: CheckOptions['mode'];\n /**\n * How permission and role conditions combine when both are provided.\n * Default: `and` (must satisfy both).\n */\n combine?: 'and' | 'or';\n children: ReactNode;\n /** Fallback when access is denied. */\n fallback?: ReactNode;\n}\n\nfunction evaluateAccess(\n hasPermission: (c: PermissionCode | PermissionCode[], o?: CheckOptions) => boolean,\n hasRole: (c: RoleCode | RoleCode[], o?: CheckOptions) => boolean,\n props: Pick<CanProps, 'permission' | 'role' | 'mode' | 'combine'>,\n): boolean {\n const { permission, role, mode, combine = 'and' } = props;\n const options: CheckOptions = { mode };\n\n const hasPermCheck = permission !== undefined;\n const hasRoleCheck = role !== undefined;\n\n if (!hasPermCheck && !hasRoleCheck) return true;\n\n const permOk = hasPermCheck ? hasPermission(permission!, options) : true;\n const roleOk = hasRoleCheck ? hasRole(role!, options) : true;\n\n if (hasPermCheck && hasRoleCheck) {\n return combine === 'or' ? permOk || roleOk : permOk && roleOk;\n }\n\n return hasPermCheck ? permOk : roleOk;\n}\n\n/**\n * Conditionally render children based on permission / role.\n *\n * @example\n * <Can permission=\"user:edit\">\n * <button>Edit</button>\n * </Can>\n *\n * <Can permission={['user:edit', 'user:delete']} mode=\"all\" fallback={null}>\n * <AdminPanel />\n * </Can>\n */\nexport function Can({\n permission,\n role,\n mode,\n combine,\n children,\n fallback = null,\n}: CanProps) {\n const { hasPermission, hasRole } = usePermission();\n const allowed = evaluateAccess(hasPermission, hasRole, {\n permission,\n role,\n mode,\n combine,\n });\n\n return <>{allowed ? children : fallback}</>;\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useState,\n type CSSProperties,\n type FormEvent,\n type ReactNode,\n} from 'react';\nimport {\n RESOURCE_PRIVATE_OPTIONS,\n RESOURCE_STATUS_ENABLED,\n RESOURCE_STATUS_OPTIONS,\n type AuthorizationResource,\n type AuthorizationResourceApi,\n type AuthorizationResourceFormValues,\n type PageDirection,\n} from '../resources';\n\nconst PAGE_SIZE_OPTIONS = ['10', '20', '50', '100'];\n\nconst emptyForm = (): AuthorizationResourceFormValues => ({\n name: '',\n identification: '',\n status: RESOURCE_STATUS_ENABLED,\n private: false,\n description: '',\n});\n\nexport type ResourceManagerProps = {\n api: AuthorizationResourceApi;\n title?: string;\n pageSize?: string;\n /** 自定义顶部右侧操作区 */\n toolbarExtra?: ReactNode;\n};\n\nexport function ResourceManager({\n api,\n title = '权限点管理',\n pageSize: initialPageSize = '20',\n toolbarExtra,\n}: ResourceManagerProps) {\n const [records, setRecords] = useState<AuthorizationResource[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [pageSize, setPageSize] = useState(initialPageSize);\n const [pageToken, setPageToken] = useState('');\n const [hasPreviousPage, setHasPreviousPage] = useState(false);\n const [hasNextPage, setHasNextPage] = useState(false);\n\n const [dialogOpen, setDialogOpen] = useState(false);\n const [editing, setEditing] = useState<AuthorizationResource | null>(null);\n const [form, setForm] = useState<AuthorizationResourceFormValues>(emptyForm);\n const [saving, setSaving] = useState(false);\n\n const loadList = useCallback(\n async (direction: PageDirection = 'current', token = pageToken) => {\n setLoading(true);\n setError('');\n try {\n const result = await api.list({\n pagination: {\n pageToken: token,\n pageSize,\n pageDirection: direction,\n },\n });\n setRecords(result.records);\n setPageToken(result.pageToken);\n setHasPreviousPage(result.hasPreviousPage);\n setHasNextPage(result.hasNextPage);\n } catch (err) {\n setError(err instanceof Error ? err.message : '加载失败');\n } finally {\n setLoading(false);\n }\n },\n [api, pageSize, pageToken],\n );\n\n useEffect(() => {\n void loadList('current', '');\n // 仅 pageSize / api 变化时重置首页\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [api, pageSize]);\n\n const openCreate = () => {\n setEditing(null);\n setForm(emptyForm());\n setDialogOpen(true);\n };\n\n const openEdit = (row: AuthorizationResource) => {\n setEditing(row);\n setForm({\n name: row.name,\n identification: row.identification,\n status: row.status,\n private: row.private,\n description: row.description,\n });\n setDialogOpen(true);\n };\n\n const closeDialog = () => {\n if (saving) return;\n setDialogOpen(false);\n };\n\n const handleSubmit = async (event: FormEvent) => {\n event.preventDefault();\n if (!form.name.trim()) {\n setError('请填写权限名称');\n return;\n }\n if (!form.identification.trim()) {\n setError('请填写接口标识');\n return;\n }\n\n setSaving(true);\n setError('');\n try {\n if (editing) {\n await api.update(editing.resourceId, form);\n } else {\n await api.create(form);\n }\n setDialogOpen(false);\n await loadList('current', '');\n } catch (err) {\n setError(err instanceof Error ? err.message : '保存失败');\n } finally {\n setSaving(false);\n }\n };\n\n const handleDelete = async (row: AuthorizationResource) => {\n if (!window.confirm(`确认删除权限点「${row.name}」?`)) return;\n setError('');\n try {\n await api.remove(row.resourceId);\n await loadList('current', '');\n } catch (err) {\n setError(err instanceof Error ? err.message : '删除失败');\n }\n };\n\n const statusLabel = useMemo(\n () =>\n Object.fromEntries(RESOURCE_STATUS_OPTIONS.map((o) => [o.value, o.label])) as Record<\n number,\n string\n >,\n [],\n );\n\n return (\n <div style={styles.root}>\n <div style={styles.toolbar}>\n <h2 style={styles.title}>{title}</h2>\n <div style={styles.toolbarRight}>\n {toolbarExtra}\n <button type=\"button\" style={styles.primaryBtn} onClick={openCreate}>\n 新增\n </button>\n </div>\n </div>\n\n {error ? <div style={styles.error}>{error}</div> : null}\n\n <div style={styles.tableWrap}>\n <table style={styles.table}>\n <thead>\n <tr>\n <th style={styles.th}>权限名称</th>\n <th style={styles.th}>接口标识</th>\n <th style={styles.th}>描述</th>\n <th style={{ ...styles.th, width: 90 }}>状态</th>\n <th style={{ ...styles.th, width: 140 }}>操作</th>\n </tr>\n </thead>\n <tbody>\n {loading ? (\n <tr>\n <td colSpan={5} style={styles.empty}>\n 加载中…\n </td>\n </tr>\n ) : records.length === 0 ? (\n <tr>\n <td colSpan={5} style={styles.empty}>\n 暂无数据\n </td>\n </tr>\n ) : (\n records.map((row) => (\n <tr key={row.resourceId}>\n <td style={styles.td}>{row.name}</td>\n <td style={styles.td}>\n <code style={styles.code}>{row.identification}</code>\n </td>\n <td style={styles.td}>{row.description || '—'}</td>\n <td style={styles.td}>\n <span\n style={{\n ...styles.badge,\n background:\n row.status === RESOURCE_STATUS_ENABLED ? '#e8f7ef' : '#f4f4f5',\n color: row.status === RESOURCE_STATUS_ENABLED ? '#067647' : '#667085',\n }}\n >\n {statusLabel[row.status] ?? row.status}\n </span>\n </td>\n <td style={styles.td}>\n <button type=\"button\" style={styles.linkBtn} onClick={() => openEdit(row)}>\n 编辑\n </button>\n <button\n type=\"button\"\n style={{ ...styles.linkBtn, color: '#d92d20' }}\n onClick={() => void handleDelete(row)}\n >\n 删除\n </button>\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n\n <div style={styles.pagination}>\n <label style={styles.pageSize}>\n 每页\n <select\n value={pageSize}\n onChange={(e) => {\n setPageToken('');\n setPageSize(e.target.value);\n }}\n style={styles.select}\n >\n {PAGE_SIZE_OPTIONS.map((size) => (\n <option key={size} value={size}>\n {size}\n </option>\n ))}\n </select>\n </label>\n <div style={styles.pageBtns}>\n <button\n type=\"button\"\n style={styles.secondaryBtn}\n disabled={!hasPreviousPage || loading}\n onClick={() => void loadList('previous')}\n >\n 上一页\n </button>\n <button\n type=\"button\"\n style={styles.secondaryBtn}\n disabled={!hasNextPage || loading}\n onClick={() => void loadList('next')}\n >\n 下一页\n </button>\n </div>\n </div>\n\n {dialogOpen ? (\n <div style={styles.mask} onClick={closeDialog}>\n <div\n style={styles.dialog}\n onClick={(e) => e.stopPropagation()}\n role=\"dialog\"\n aria-modal=\"true\"\n >\n <div style={styles.dialogHeader}>\n <h3 style={styles.dialogTitle}>{editing ? '编辑权限点' : '新增权限点'}</h3>\n <button type=\"button\" style={styles.iconBtn} onClick={closeDialog} aria-label=\"关闭\">\n ×\n </button>\n </div>\n <form style={styles.form} onSubmit={(e) => void handleSubmit(e)}>\n <label style={styles.field}>\n <span style={styles.label}>权限名称</span>\n <input\n style={styles.input}\n value={form.name}\n onChange={(e) => setForm((prev) => ({ ...prev, name: e.target.value }))}\n placeholder=\"请输入权限名称\"\n required\n />\n </label>\n <label style={styles.field}>\n <span style={styles.label}>接口标识</span>\n <input\n style={styles.input}\n value={form.identification}\n onChange={(e) =>\n setForm((prev) => ({ ...prev, identification: e.target.value }))\n }\n placeholder=\"如 user:list\"\n required\n />\n </label>\n <label style={styles.field}>\n <span style={styles.label}>状态</span>\n <select\n style={styles.input}\n value={form.status}\n onChange={(e) =>\n setForm((prev) => ({\n ...prev,\n status: Number(e.target.value) as 0 | 1,\n }))\n }\n >\n {RESOURCE_STATUS_OPTIONS.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n <label style={styles.field}>\n <span style={styles.label}>私有资源</span>\n <select\n style={styles.input}\n value={form.private ? '1' : '0'}\n onChange={(e) =>\n setForm((prev) => ({ ...prev, private: e.target.value === '1' }))\n }\n >\n {RESOURCE_PRIVATE_OPTIONS.map((opt) => (\n <option key={String(opt.value)} value={opt.value ? '1' : '0'}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n <label style={styles.field}>\n <span style={styles.label}>描述</span>\n <textarea\n style={{ ...styles.input, minHeight: 88, resize: 'vertical' }}\n value={form.description}\n onChange={(e) =>\n setForm((prev) => ({ ...prev, description: e.target.value }))\n }\n placeholder=\"请输入描述\"\n />\n </label>\n <div style={styles.dialogFooter}>\n <button type=\"button\" style={styles.secondaryBtn} onClick={closeDialog}>\n 取消\n </button>\n <button type=\"submit\" style={styles.primaryBtn} disabled={saving}>\n {saving ? '保存中…' : '保存'}\n </button>\n </div>\n </form>\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\nconst styles: Record<string, CSSProperties> = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 16,\n padding: 16,\n color: '#101828',\n fontFamily:\n '\"PingFang SC\", \"Microsoft YaHei\", -apple-system, BlinkMacSystemFont, sans-serif',\n },\n toolbar: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 12,\n },\n title: { margin: 0, fontSize: 18, fontWeight: 600 },\n toolbarRight: { display: 'flex', alignItems: 'center', gap: 8 },\n error: {\n padding: '10px 12px',\n borderRadius: 8,\n background: '#fef3f2',\n color: '#b42318',\n fontSize: 13,\n },\n tableWrap: {\n overflow: 'auto',\n border: '1px solid #eaecf0',\n borderRadius: 10,\n background: '#fff',\n },\n table: { width: '100%', borderCollapse: 'collapse', minWidth: 720 },\n th: {\n textAlign: 'left',\n padding: '12px 14px',\n fontSize: 13,\n fontWeight: 600,\n color: '#475467',\n background: '#f9fafb',\n borderBottom: '1px solid #eaecf0',\n },\n td: {\n padding: '12px 14px',\n fontSize: 14,\n borderBottom: '1px solid #f2f4f7',\n verticalAlign: 'middle',\n },\n empty: {\n padding: 28,\n textAlign: 'center',\n color: '#98a2b3',\n fontSize: 14,\n },\n code: {\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: 13,\n background: '#f2f4f7',\n padding: '2px 6px',\n borderRadius: 4,\n },\n badge: {\n display: 'inline-block',\n padding: '2px 8px',\n borderRadius: 999,\n fontSize: 12,\n fontWeight: 500,\n },\n linkBtn: {\n border: 'none',\n background: 'transparent',\n color: '#049BAD',\n cursor: 'pointer',\n padding: '0 8px 0 0',\n fontSize: 13,\n },\n pagination: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 12,\n },\n pageSize: { display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: '#475467' },\n pageBtns: { display: 'flex', gap: 8 },\n primaryBtn: {\n border: 'none',\n background: '#049BAD',\n color: '#fff',\n borderRadius: 8,\n padding: '8px 14px',\n cursor: 'pointer',\n fontSize: 14,\n },\n secondaryBtn: {\n border: '1px solid #d0d5dd',\n background: '#fff',\n color: '#344054',\n borderRadius: 8,\n padding: '8px 14px',\n cursor: 'pointer',\n fontSize: 14,\n },\n select: {\n border: '1px solid #d0d5dd',\n borderRadius: 6,\n padding: '4px 8px',\n fontSize: 13,\n },\n mask: {\n position: 'fixed',\n inset: 0,\n background: 'rgba(16, 24, 40, 0.45)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 1000,\n padding: 16,\n },\n dialog: {\n width: '100%',\n maxWidth: 480,\n background: '#fff',\n borderRadius: 12,\n boxShadow: '0 20px 40px rgba(16,24,40,0.18)',\n },\n dialogHeader: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '14px 16px',\n borderBottom: '1px solid #eaecf0',\n },\n dialogTitle: { margin: 0, fontSize: 16, fontWeight: 600 },\n iconBtn: {\n border: 'none',\n background: 'transparent',\n fontSize: 22,\n lineHeight: 1,\n cursor: 'pointer',\n color: '#667085',\n },\n form: { display: 'flex', flexDirection: 'column', gap: 12, padding: 16 },\n field: { display: 'flex', flexDirection: 'column', gap: 6 },\n label: { fontSize: 13, color: '#344054', fontWeight: 500 },\n input: {\n border: '1px solid #d0d5dd',\n borderRadius: 8,\n padding: '8px 10px',\n fontSize: 14,\n outline: 'none',\n },\n dialogFooter: {\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 8,\n paddingTop: 4,\n },\n};\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_core","import_resources"]}