@fudanda/admin-antd 2.20261109.1-beta.1 → 2.20261109.1-beta.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.
- package/dist/chunks/ApiTokensPage-w3JGRNQC.js +2 -0
- package/dist/chunks/ApiTokensPage-w3JGRNQC.js.map +1 -0
- package/dist/chunks/{App-CfQx7jWq.js → App-nh6_qOo8.js} +5 -5
- package/dist/chunks/{App-CfQx7jWq.js.map → App-nh6_qOo8.js.map} +1 -1
- package/dist/chunks/{AppModal-CVoUC2t3.js → AppModal-CEouaU03.js} +2 -2
- package/dist/chunks/{AppModal-CVoUC2t3.js.map → AppModal-CEouaU03.js.map} +1 -1
- package/dist/chunks/{ArcBaseAdmin-DQyddbFC.js → ArcBaseAdmin-CX7fQz4x.js} +2 -2
- package/dist/chunks/{ArcBaseAdmin-DQyddbFC.js.map → ArcBaseAdmin-CX7fQz4x.js.map} +1 -1
- package/dist/chunks/{DepartmentsPage-CQx53QGE.js → DepartmentsPage-BdD9VfDI.js} +2 -2
- package/dist/chunks/{DepartmentsPage-CQx53QGE.js.map → DepartmentsPage-BdD9VfDI.js.map} +1 -1
- package/dist/chunks/{DictsPage-BGnamkWk.js → DictsPage-fxBdV1-3.js} +2 -2
- package/dist/chunks/{DictsPage-BGnamkWk.js.map → DictsPage-fxBdV1-3.js.map} +1 -1
- package/dist/chunks/{EntityContextRuntime-CbzeMNXR.js → EntityContextRuntime-CMhoj6qe.js} +2 -2
- package/dist/chunks/{EntityContextRuntime-CbzeMNXR.js.map → EntityContextRuntime-CMhoj6qe.js.map} +1 -1
- package/dist/chunks/EntityContextRuntime-Dc89ZSnM.js +1 -0
- package/dist/chunks/{ExportButton-sMPAV2hd.js → ExportButton-DGxB2tcu.js} +2 -2
- package/dist/chunks/{ExportButton-sMPAV2hd.js.map → ExportButton-DGxB2tcu.js.map} +1 -1
- package/dist/chunks/{FileViewerPreviewPanel-Rti7pUhU.js → FileViewerPreviewPanel-BMZ7FdKV.js} +3 -3
- package/dist/chunks/{FileViewerPreviewPanel-Rti7pUhU.js.map → FileViewerPreviewPanel-BMZ7FdKV.js.map} +1 -1
- package/dist/chunks/{FilesPage-D_iYsUwl.js → FilesPage-DrgWELKy.js} +3 -3
- package/dist/chunks/{FilesPage-D_iYsUwl.js.map → FilesPage-DrgWELKy.js.map} +1 -1
- package/dist/chunks/{IdentitySecurityPage-rDYX5ksX.js → IdentitySecurityPage-BjTKvr-O.js} +2 -2
- package/dist/chunks/{IdentitySecurityPage-rDYX5ksX.js.map → IdentitySecurityPage-BjTKvr-O.js.map} +1 -1
- package/dist/chunks/{LogStatsScaffold-CMIz4z0a.js → LogStatsScaffold-DaB0JeAN.js} +2 -2
- package/dist/chunks/{LogStatsScaffold-CMIz4z0a.js.map → LogStatsScaffold-DaB0JeAN.js.map} +1 -1
- package/dist/chunks/{LoginLogsPage-Bv5pPJb2.js → LoginLogsPage-VmYC7i6q.js} +2 -2
- package/dist/chunks/{LoginLogsPage-Bv5pPJb2.js.map → LoginLogsPage-VmYC7i6q.js.map} +1 -1
- package/dist/chunks/{LoginLogsTable-DYcTx2oR.js → LoginLogsTable-CULcc_e8.js} +2 -2
- package/dist/chunks/{LoginLogsTable-DYcTx2oR.js.map → LoginLogsTable-CULcc_e8.js.map} +1 -1
- package/dist/chunks/{MarkdownPreviewPanel-lqs6AsoN.js → MarkdownPreviewPanel-CBcPc7Wv.js} +2 -2
- package/dist/chunks/{MarkdownPreviewPanel-lqs6AsoN.js.map → MarkdownPreviewPanel-CBcPc7Wv.js.map} +1 -1
- package/dist/chunks/{MasterDetailLayout-B5uqvh98.js → MasterDetailLayout-ByIBpmkZ.js} +2 -2
- package/dist/chunks/{MasterDetailLayout-B5uqvh98.js.map → MasterDetailLayout-ByIBpmkZ.js.map} +1 -1
- package/dist/chunks/{McpSettingsPage-Cdej9Evi.js → McpSettingsPage-C5V_rj2V.js} +2 -2
- package/dist/chunks/{McpSettingsPage-Cdej9Evi.js.map → McpSettingsPage-C5V_rj2V.js.map} +1 -1
- package/dist/chunks/{MemberAssignmentSheet-AKvLbbYW.js → MemberAssignmentSheet-DL0fg1Yf.js} +2 -2
- package/dist/chunks/{MemberAssignmentSheet-AKvLbbYW.js.map → MemberAssignmentSheet-DL0fg1Yf.js.map} +1 -1
- package/dist/chunks/{MenuCommandPalette-ia0pSIFg.js → MenuCommandPalette-C2PvK3Gh.js} +2 -2
- package/dist/chunks/{MenuCommandPalette-ia0pSIFg.js.map → MenuCommandPalette-C2PvK3Gh.js.map} +1 -1
- package/dist/chunks/{MenusPage-Bh55bvKH.js → MenusPage-Bytd1HlW.js} +2 -2
- package/dist/chunks/{MenusPage-Bh55bvKH.js.map → MenusPage-Bytd1HlW.js.map} +1 -1
- package/dist/chunks/{MonacoPreviewPanel-CT_sjf7Z.js → MonacoPreviewPanel-BZrNIcFZ.js} +2 -2
- package/dist/chunks/{MonacoPreviewPanel-CT_sjf7Z.js.map → MonacoPreviewPanel-BZrNIcFZ.js.map} +1 -1
- package/dist/chunks/{NavListPanel-DMIUMh7q.js → NavListPanel-zwUDIYSP.js} +2 -2
- package/dist/chunks/{NavListPanel-DMIUMh7q.js.map → NavListPanel-zwUDIYSP.js.map} +1 -1
- package/dist/chunks/{OperationLogsPage-7XVfmhxP.js → OperationLogsPage-D2BQdGNp.js} +2 -2
- package/dist/chunks/{OperationLogsPage-7XVfmhxP.js.map → OperationLogsPage-D2BQdGNp.js.map} +1 -1
- package/dist/chunks/{OperationLogsTable-gp-WZxiF.js → OperationLogsTable-DaaON4QR.js} +3 -3
- package/dist/chunks/{OperationLogsTable-gp-WZxiF.js.map → OperationLogsTable-DaaON4QR.js.map} +1 -1
- package/dist/chunks/{PDFPreviewPanel-CyfhyWav.js → PDFPreviewPanel-CMmnWBKW.js} +3 -3
- package/dist/chunks/{PDFPreviewPanel-CyfhyWav.js.map → PDFPreviewPanel-CMmnWBKW.js.map} +1 -1
- package/dist/chunks/{PositionsPage-Bwua1vNV.js → PositionsPage-CBZITssT.js} +2 -2
- package/dist/chunks/{PositionsPage-Bwua1vNV.js.map → PositionsPage-CBZITssT.js.map} +1 -1
- package/dist/chunks/{PreferencesSheetBody-C80D3dOM.js → PreferencesSheetBody-B0poTPEA.js} +2 -2
- package/dist/chunks/{PreferencesSheetBody-C80D3dOM.js.map → PreferencesSheetBody-B0poTPEA.js.map} +1 -1
- package/dist/chunks/{ProfilePage-DeTw-59a.js → ProfilePage-DLhacdWt.js} +2 -2
- package/dist/chunks/{ProfilePage-DeTw-59a.js.map → ProfilePage-DLhacdWt.js.map} +1 -1
- package/dist/chunks/{ProjectInfoPage-Bqn3gfXa.js → ProjectInfoPage-CJpGxpu5.js} +2 -2
- package/dist/chunks/{ProjectInfoPage-Bqn3gfXa.js.map → ProjectInfoPage-CJpGxpu5.js.map} +1 -1
- package/dist/chunks/{RelationPanel-Bio-ig-l.js → RelationPanel-BsbfEDo2.js} +2 -2
- package/dist/chunks/{RelationPanel-Bio-ig-l.js.map → RelationPanel-BsbfEDo2.js.map} +1 -1
- package/dist/chunks/{RolesPage-fwUSs2HR.js → RolesPage-46dzdiah.js} +2 -2
- package/dist/chunks/{RolesPage-fwUSs2HR.js.map → RolesPage-46dzdiah.js.map} +1 -1
- package/dist/chunks/{SessionConflictModal-Dw4opoNP.js → SessionConflictModal-Bm38eExL.js} +2 -2
- package/dist/chunks/{SessionConflictModal-Dw4opoNP.js.map → SessionConflictModal-Bm38eExL.js.map} +1 -1
- package/dist/chunks/SettingModuleDetail-BjxUJeH5.js +17 -0
- package/dist/chunks/SettingModuleDetail-BjxUJeH5.js.map +1 -0
- package/dist/chunks/{SettingsPage-Cy5-q-P6.js → SettingsPage-C32Vuizm.js} +2 -2
- package/dist/chunks/{SettingsPage-Cy5-q-P6.js.map → SettingsPage-C32Vuizm.js.map} +1 -1
- package/dist/chunks/{StatCard-BROG4NSp.js → StatCard-CRPfkSBY.js} +2 -2
- package/dist/chunks/{StatCard-BROG4NSp.js.map → StatCard-CRPfkSBY.js.map} +1 -1
- package/dist/chunks/{UserGroupsPage-CsTBkUPy.js → UserGroupsPage-08G5MdGm.js} +2 -2
- package/dist/chunks/{UserGroupsPage-CsTBkUPy.js.map → UserGroupsPage-08G5MdGm.js.map} +1 -1
- package/dist/chunks/{UserLogsPanels-3u8Z93YU.js → UserLogsPanels-nbIrMym9.js} +2 -2
- package/dist/chunks/{UserLogsPanels-3u8Z93YU.js.map → UserLogsPanels-nbIrMym9.js.map} +1 -1
- package/dist/chunks/{UserTransferSelect-ChLj4EkS.js → UserTransferSelect-C8betaWG.js} +2 -2
- package/dist/chunks/{UserTransferSelect-ChLj4EkS.js.map → UserTransferSelect-C8betaWG.js.map} +1 -1
- package/dist/chunks/{UsersPage-CfNnQJi4.js → UsersPage-BjTiNEqF.js} +2 -2
- package/dist/chunks/{UsersPage-CfNnQJi4.js.map → UsersPage-BjTiNEqF.js.map} +1 -1
- package/dist/chunks/{browser-BKLM0ThC-D0TgzKTC.js → browser-BKLM0ThC-Cp7Gi4-F.js} +1 -1
- package/dist/chunks/{code-BkkeN2fd.js → code-LswxAr98.js} +1 -1
- package/dist/chunks/{direct-engine-m32m22nx.js → direct-engine-Dv_6v4sx.js} +1 -1
- package/dist/chunks/{html-BGNWR_Bp.js → html-BokjxlLb.js} +1 -1
- package/dist/chunks/{line-CsTeuEcK.js → line-Bqh6atHH.js} +1 -1
- package/dist/chunks/{lrc-D6gjnGZ5.js → lrc-T5e1svZG.js} +1 -1
- package/dist/chunks/{markdown-BglUe9j8.js → markdown-BpWokN1s.js} +1 -1
- package/dist/chunks/{patch-C97Yl3jr.js → patch-BYVX5C9G.js} +1 -1
- package/dist/chunks/{worker-engine-B7_3qQVS.js → worker-engine-CtUAeI4G.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/{src-DAkFn9SG.js → src-D6UlLiVN.js} +2 -2
- package/dist/{src-DAkFn9SG.js.map → src-D6UlLiVN.js.map} +1 -1
- package/package.json +9 -9
- package/dist/chunks/ApiTokensPage-DiRMgViD.js +0 -2
- package/dist/chunks/ApiTokensPage-DiRMgViD.js.map +0 -1
- package/dist/chunks/EntityContextRuntime-C9q95WDf.js +0 -1
- package/dist/chunks/SettingModuleDetail-I9CSJ-fh.js +0 -17
- package/dist/chunks/SettingModuleDetail-I9CSJ-fh.js.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{n as e}from"./rolldown-runtime-Bruge11p.js";import{E as t,It as n,M as r,O as i,R as a,Rt as o,T as s,U as c,f as l,m as u,r as d,t as f,vt as p,yt as m,zt as h}from"./clipboard-dpqHdCyy.js";import{i as g,n as _}from"./feedback-B1UL2ETz.js";import{n as v,t as ee}from"./circle-check-big-BacE3WpZ.js";import{n as y,t as b}from"./plus-C_Qg8uc3.js";import{n as te,t as x}from"./useCrudOperationColumn-CPAzNGXp.js";import{n as ne}from"./listTableProps-BAghXGb4.js";import{i as S,n as C,r as w}from"./table-columns-CvT6OHd2.js";import{a as T,o as re,r as E,t as D}from"./EditFormModal-DVQksS9R.js";import{n as O,t as k}from"./ConfigurableTable-8sYmeul2.js";import{useEffect as A,useState as j}from"react";import{Fragment as M,jsx as N,jsxs as P}from"react/jsx-runtime";import{abortSubmit as F}from"@fudanda/admin-antd/core/lib/abort-submit";import{useLocation as I}from"react-router-dom";import{usePagination as L}from"@fudanda/admin-antd/core/hooks/usePagination";import{useAuth as R}from"@fudanda/admin-antd/core/hooks/useAuth";import{TOKEN_PERMISSION_KIND_LABELS as z,tokenPermissionGroups as B,tokenPermissionPreset as V,tokenPermissionPreview as H,useApiKeyPermissions as U,useApiTokenDetail as W,useApiTokenSecret as G,useDeleteApiToken as K,useProfileApiTokens as q,useSaveApiToken as J}from"@fudanda/admin-antd/core/hooks/queries/profile";function Y({permissions:e}){let t=H(e);return/* @__PURE__ */ P(`div`,{className:`token-permission-preview`,children:[/* @__PURE__ */ P(`p`,{role:`status`,children:[`已选 `,new Set(e).size,` 项权限 · 内置 MCP 工具 `,t.tools.length,` 项 · 已知 API 接口 `,t.operations.length,` 项`]}),/* @__PURE__ */ N(`p`,{children:`实际访问仍受账号当前权限、数据范围和宿主已开放接口限制。这些权限也可用于普通 API,MCP 查询预设不限制 API Key 的接入方式。`}),t.tools.length>0&&/* @__PURE__ */ N(`div`,{className:`token-permission-tools`,children:t.tools.map(e=>/* @__PURE__ */ P(i,{children:[e.label,` `,/* @__PURE__ */ N(`code`,{children:e.name})]},e.name))}),t.operations.length>0&&/* @__PURE__ */ P(`details`,{children:[/* @__PURE__ */ N(`summary`,{children:`查看已知 API 接口`}),/* @__PURE__ */ N(`ul`,{children:t.operations.map(e=>/* @__PURE__ */ N(`li`,{children:/* @__PURE__ */ P(`code`,{children:[e.method,` `,e.path]})},e.id))})]}),t.extensions.length>0&&/* @__PURE__ */ P(`p`,{children:[`扩展权限的具体能力请核对宿主说明:`,t.extensions.join(`、`),`。`]})]})}function ie({permissions:e}){return/* @__PURE__ */ P(M,{children:[B(e).map(e=>/* @__PURE__ */ P(`section`,{className:`token-permission-group`,children:[/* @__PURE__ */ N(`h4`,{children:e.label}),e.items.map(e=>/* @__PURE__ */ P(`div`,{className:`token-permission-row`,children:[/* @__PURE__ */ P(`span`,{className:`token-permission-label`,children:[e.label,/* @__PURE__ */ N(`code`,{children:e.code})]}),/* @__PURE__ */ N(i,{className:`token-permission-kind`,children:z[e.kind]})]},e.code))]},e.label)),/* @__PURE__ */ N(Y,{permissions:e})]})}function ae({permissions:e,onDetails:t}){let n=B(e);return/* @__PURE__ */ P(`div`,{className:`token-permission-summary`,children:[/* @__PURE__ */ N(`span`,{children:e.length?`${new Set(e).size} 项 · ${n.slice(0,3).map(e=>e.label).join(`、`)}${n.length>3?`等`:``}`:`未授予权限`}),/* @__PURE__ */ N(u,{theme:`borderless`,size:`small`,onClick:t,children:`查看范围`})]})}function oe({value:e=[],onChange:t,permissions:n,disabled:r}){let[a,c]=j(``),d=B(n,a),f=new Set(e),p=e=>t?.(V(n,e)),m=(n,r)=>t?.(r?[.../* @__PURE__ */ new Set([...e,n])]:e.filter(e=>e!==n));return/* @__PURE__ */ P(`div`,{className:`token-permission-picker`,children:[/* @__PURE__ */ P(s,{wrap:!0,children:[/* @__PURE__ */ N(u,{size:`small`,disabled:r||!V(n,`mcp`).length,onClick:()=>p(`mcp`),children:`MCP 查询`}),/* @__PURE__ */ N(u,{size:`small`,disabled:r||!V(n,`read`).length,onClick:()=>p(`read`),children:`API 只读`}),/* @__PURE__ */ N(u,{size:`small`,disabled:r||!e.length,onClick:()=>t?.([]),children:`清空选择`})]}),/* @__PURE__ */ N(`p`,{className:`token-permission-hint`,children:`快捷选择会替换当前勾选;也可逐项自定义。只读按已知接口判断,未知扩展权限需手动选择。`}),/* @__PURE__ */ N(h,{"aria-label":`搜索权限`,placeholder:`搜索模块、中文名称或权限代码`,value:a,onChange:c,showClear:!0,disabled:r}),/* @__PURE__ */ P(`div`,{className:`token-permission-options`,"aria-label":`可授予权限`,children:[d.map(e=>/* @__PURE__ */ P(`fieldset`,{className:`token-permission-group`,children:[/* @__PURE__ */ N(`legend`,{children:e.label}),e.items.map(e=>/* @__PURE__ */ P(`div`,{className:`token-permission-row`,children:[/* @__PURE__ */ N(o,{disabled:r,checked:f.has(e.code),onChange:t=>m(e.code,!!t.target.checked),children:/* @__PURE__ */ P(`span`,{className:`token-permission-label`,children:[e.label,/* @__PURE__ */ N(`code`,{children:e.code})]})}),/* @__PURE__ */ N(i,{className:`token-permission-kind`,children:z[e.kind]})]},e.code))]},e.label)),!d.length&&/* @__PURE__ */ N(`p`,{children:n.length?`没有匹配的权限,已选项仍然保留。`:`当前没有可授予的权限。`})]}),e.some(e=>!n.includes(e))&&/* @__PURE__ */ N(l,{type:`warning`,description:`部分已选权限当前不可授予,请清空并重新选择。`}),/* @__PURE__ */ N(Y,{permissions:e})]})}var X;function Z(){return(Z=e((()=>{r(),X=c(oe)})))()}function se(){let{user:e}=R(),n=e.id,r=I().pathname===`/system/api-tokens`,[i,o]=j(null),s=G(n,r),c=s.value,[d,m]=j(!1),h=q(r),v=L({resetKey:n}),y=U(r),x=J(n,r),S=K(),T=re({save:{mutateAsync:({id:e,values:t})=>x.mutateAsync({id:e,values:t}),isPending:x.isPending},useDetail:W,toValues:e=>({name:e.name,expiresAt:`expiresAt`in e?e.expiresAt:void 0,permissions:`permissions`in e?e.permissions:[]}),beforeSave:e=>{let t=e.name.trim();return t||(g.error(`请填写 API Key 名称`),F(`validation`)),e.permissions?.length||(g.error(`请选择 API Key 权限`),F(`validation`)),{name:t,...e.expiresAt?{expiresAt:new Date(e.expiresAt).toISOString()}:{},permissions:e.permissions}},defaults:{name:``,permissions:[]},successMessage:({isEdit:e})=>e?`API Key 已更新`:null,onSaved:e=>{e&&`token`in e&&(m(!1),s.showCreated(e))}}),E=T.close;A(()=>{E(),o(null),m(!1)},[r,n,E]);async function O(e){await S.mutateAsync({params:{id:e}}),g.success(`API Key 已撤销`)}function M(e){f(e).then(e=>{e?(m(!0),setTimeout(()=>m(!1),2e3)):g.error(`复制失败,请手动复制`)})}let z=te({edit:e=>T.openEdit(e),remove:e=>O(e.id),title:`确定要撤销该 API Key 吗?`,content:`撤销后将无法恢复,使用该 API Key 的调用将立即失效。`,successMessage:null,removeLabel:`撤销`,width:200,extra:e=>[{key:`view`,label:`查看 API Key`,disabled:!e.canReveal,onClick:()=>{m(!1),s.reveal(e.id)}}]});return/* @__PURE__ */ P(`div`,{className:`page-container page-container--stretch`,children:[/* @__PURE__ */ P(Q,{type:`tertiary`,size:`small`,style:{display:`block`},children:[`API Key 可通过 `,/* @__PURE__ */ N(`code`,{children:`Authorization: Bearer <API_KEY>`}),` 头访问 API,每人最多 20 个。`]}),/* @__PURE__ */ N(k,{...ne(h,{pagination:v.buildPagination}),headerTitle:`API Key`,toolBarRender:()=>[/* @__PURE__ */ N(u,{type:`primary`,icon:/* @__PURE__ */ N(b,{size:14}),onClick:T.openCreate,children:`新建 API Key`},`create`)],columns:[{title:`名称`,dataIndex:`name`,minWidth:150,render:e=>/* @__PURE__ */ N(Q,{strong:!0,children:e})},{title:`权限范围`,dataIndex:`permissions`,width:260,render:(e,t)=>/* @__PURE__ */ N(ae,{permissions:e,onDetails:()=>o(t)})},{title:`API Key 前缀`,dataIndex:`tokenPrefix`,width:180,render:(e,t)=>/* @__PURE__ */ P(`div`,{children:[/* @__PURE__ */ N(`code`,{style:{fontSize:12},children:e}),!t.canReveal&&/* @__PURE__ */ N(`div`,{children:/* @__PURE__ */ N(Q,{type:`tertiary`,size:`small`,children:`仅存摘要,无法查看原文`})})]})},w(`最后使用`,`lastUsedAt`,{empty:`未使用`}),w(`过期时间`,`expiresAt`,{empty:`永久有效`}),C,z]}),r&&/* @__PURE__ */ P(D,{modal:T,title:T.isEdit?`编辑 API Key`:`新建 API Key`,okText:T.isEdit?`保存`:`创建`,cancelText:`取消`,width:740,centered:!0,formProps:{labelPosition:`top`},okButtonProps:{...T.modalProps.okButtonProps,disabled:T.detailLoading||y.isPending||!!y.error},children:[/* @__PURE__ */ N(a.Input,{field:`name`,maxLength:64,label:`名称`,placeholder:`如:本地开发、CI/CD 环境`,rules:[{required:!0,message:`请填写 API Key 名称`}],style:{width:`100%`}}),y.error&&/* @__PURE__ */ N(l,{type:`danger`,description:/* @__PURE__ */ P(`span`,{children:[`权限范围加载失败。`,/* @__PURE__ */ N(u,{theme:`borderless`,onClick:()=>void y.refetch(),children:`重试`})]})}),/* @__PURE__ */ N(X,{field:`permissions`,label:`权限范围`,permissions:y.data??[],disabled:y.isPending||!!y.error,rules:[{validator:(e,t)=>Array.isArray(t)&&t.length>0,message:`请选择至少一项权限`}],extraText:`API Key 权限不会超过账号当前权限;权限撤销、停用和改密后立即失效。`}),/* @__PURE__ */ N(a.DatePicker,{field:`expiresAt`,label:`过期时间`,type:`dateTime`,placeholder:`不填则永久有效`,style:{width:`100%`},disabledDate:e=>!!e&&e<new Date((/* @__PURE__ */ new Date()).setHours(0,0,0,0))})]}),/* @__PURE__ */ N(_,{title:i?`API Key 权限范围 · ${i.name}`:`API Key 权限范围`,visible:r&&!!i,onCancel:()=>o(null),footer:/* @__PURE__ */ N(u,{onClick:()=>o(null),children:`关闭`}),width:740,centered:!0,children:i&&/* @__PURE__ */ N(ie,{permissions:i.permissions})}),/* @__PURE__ */ P(_,{title:s.created?`API Key 创建成功`:`查看 API Key`,visible:r&&(!!c||s.pending),closeOnEsc:!0,onCancel:s.close,footer:/* @__PURE__ */ N(u,{type:`primary`,onClick:s.close,children:`关闭`}),width:520,centered:!0,children:[/* @__PURE__ */ N(Q,{type:`warning`,style:{display:`block`,marginBottom:12,padding:`8px 12px`,background:`var(--arc-antd-color-warning-light-default)`,borderRadius:`var(--arc-antd-border-radius-medium)`},children:c?.canReveal?`请妥善保管此 API Key,可在列表中再次查看或复制。`:`请立即复制并安全保存此 API Key,关闭后将无法再次查看完整内容。`}),s.pending&&/* @__PURE__ */ N(t,{}),c&&/* @__PURE__ */ P(`div`,{className:`token-display`,children:[/* @__PURE__ */ N(`code`,{style:{flex:1,wordBreak:`break-all`,fontSize:12,lineHeight:1.6},children:c.token}),/* @__PURE__ */ N(u,{icon:N(d?ee:p,{size:14}),type:d?`tertiary`:`primary`,onClick:()=>M(c.token),style:{flexShrink:0},children:d?`已复制`:`复制`})]})]})]})}var Q;function $(){return($=e((()=>{y(),m(),v(),r(),O(),E(),x(),T(),d(),S(),Z(),{Text:Q}=n})))()}$();export{se as default};
|
|
2
|
+
//# sourceMappingURL=ApiTokensPage-w3JGRNQC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiTokensPage-w3JGRNQC.js","mappings":"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","names":["TokenPermissionPreview","preview","tokenPermissionPreview","permissions","Tag","tool","operation","TokenPermissionDetails","_Fragment","tokenPermissionGroups","group","item","TOKEN_PERMISSION_KIND_LABELS","TokenPermissionSummary","groups","Button","onDetails","TokenPermissionPicker","keyword","setKeyword","useState","selected","value","selectPreset","onChange","tokenPermissionPreset","preset","toggle","checked","code","Space","disabled","Input","Checkbox","event","Banner","withField","ApiTokensPage","useAuth","ownerId","user","active","useLocation","scopeToken","setScopeToken","tokenSecret","useApiTokenSecret","createdToken","tokenCopied","setTokenCopied","apiTokensQuery","useProfileApiTokens","tokenPagination","usePagination","keyPermissionsQuery","useApiKeyPermissions","saveTokenMutation","useSaveApiToken","deleteTokenMutation","useDeleteApiToken","tokenModal","useEditModal","useApiTokenDetail","record","name","values","Toast","abortSubmit","isEdit","saved","closeEditor","useEffect","handleDeleteToken","copyToken","copyText","token","ok","tokenOperationColumn","useCrudOperationColumn","Text","ConfigurableTable","listTableProps","Plus","v","dateTimeColumn","createdAtColumn","EditFormModal","Form","FormTokenPermissionPicker","date","Modal","Spin","jsx","CheckCircle","Copy","Typography"],"ignoreList":[],"sources":["../../src/pages/system/api-tokens/TokenPermissionPicker.tsx","../../src/pages/system/api-tokens/ApiTokensPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { Banner, Button, Checkbox, Input, Space, Tag, withField } from '@/ui';\nimport {\n tokenPermissionGroups, tokenPermissionPreset,\n tokenPermissionPreview, TOKEN_PERMISSION_KIND_LABELS,\n} from '@fudanda/react-core/hooks/queries/profile';\n\ninterface PickerProps {\n value?: string[];\n onChange?: (value: string[]) => void;\n permissions: readonly string[];\n disabled?: boolean;\n}\n\nexport function TokenPermissionPreview({ permissions }: { readonly permissions: readonly string[] }) {\n const preview = tokenPermissionPreview(permissions);\n return <div className=\"token-permission-preview\">\n <p role=\"status\">已选 {new Set(permissions).size} 项权限 · 内置 MCP 工具 {preview.tools.length} 项 · 已知 API 接口 {preview.operations.length} 项</p>\n <p>实际访问仍受账号当前权限、数据范围和宿主已开放接口限制。这些权限也可用于普通 API,MCP 查询预设不限制 API Key 的接入方式。</p>\n {preview.tools.length > 0 && <div className=\"token-permission-tools\">{preview.tools.map(tool => <Tag key={tool.name}>{tool.label} <code>{tool.name}</code></Tag>)}</div>}\n {preview.operations.length > 0 && <details><summary>查看已知 API 接口</summary><ul>{preview.operations.map(operation => <li key={operation.id}><code>{operation.method} {operation.path}</code></li>)}</ul></details>}\n {preview.extensions.length > 0 && <p>扩展权限的具体能力请核对宿主说明:{preview.extensions.join('、')}。</p>}\n </div>;\n}\n\nexport function TokenPermissionDetails({ permissions }: { readonly permissions: readonly string[] }) {\n return <>\n {tokenPermissionGroups(permissions).map(group => <section className=\"token-permission-group\" key={group.label}>\n <h4>{group.label}</h4>\n {group.items.map(item => <div className=\"token-permission-row\" key={item.code}>\n <span className=\"token-permission-label\">{item.label}<code>{item.code}</code></span>\n <Tag className=\"token-permission-kind\">{TOKEN_PERMISSION_KIND_LABELS[item.kind]}</Tag>\n </div>)}\n </section>)}\n <TokenPermissionPreview permissions={permissions}/>\n </>;\n}\n\nexport function TokenPermissionSummary({ permissions, onDetails }: {\n readonly permissions: readonly string[];\n readonly onDetails: () => void;\n}) {\n const groups = tokenPermissionGroups(permissions);\n return <div className=\"token-permission-summary\">\n <span>{permissions.length ? `${new Set(permissions).size} 项 · ${groups.slice(0, 3).map(group => group.label).join('、')}${groups.length > 3 ? '等' : ''}` : '未授予权限'}</span>\n <Button theme=\"borderless\" size=\"small\" onClick={onDetails}>查看范围</Button>\n </div>;\n}\n\nexport function TokenPermissionPicker({ value = [], onChange, permissions, disabled }: Readonly<PickerProps>) {\n const [keyword, setKeyword] = useState('');\n const groups = tokenPermissionGroups(permissions, keyword);\n const selected = new Set(value);\n const selectPreset = (preset: 'mcp' | 'read') => onChange?.(tokenPermissionPreset(permissions, preset));\n const toggle = (code: string, checked: boolean) => onChange?.(checked ? [...new Set([...value, code])] : value.filter(item => item !== code));\n return <div className=\"token-permission-picker\">\n <Space wrap>\n <Button size=\"small\" disabled={disabled || !tokenPermissionPreset(permissions, 'mcp').length} onClick={() => selectPreset('mcp')}>MCP 查询</Button>\n <Button size=\"small\" disabled={disabled || !tokenPermissionPreset(permissions, 'read').length} onClick={() => selectPreset('read')}>API 只读</Button>\n <Button size=\"small\" disabled={disabled || !value.length} onClick={() => onChange?.([])}>清空选择</Button>\n </Space>\n <p className=\"token-permission-hint\">快捷选择会替换当前勾选;也可逐项自定义。只读按已知接口判断,未知扩展权限需手动选择。</p>\n <Input aria-label=\"搜索权限\" placeholder=\"搜索模块、中文名称或权限代码\" value={keyword} onChange={setKeyword} showClear disabled={disabled}/>\n <div className=\"token-permission-options\" aria-label=\"可授予权限\">\n {groups.map(group => <fieldset className=\"token-permission-group\" key={group.label}>\n <legend>{group.label}</legend>\n {group.items.map(item => <div className=\"token-permission-row\" key={item.code}>\n <Checkbox disabled={disabled} checked={selected.has(item.code)} onChange={event => toggle(item.code, Boolean(event.target.checked))}>\n <span className=\"token-permission-label\">{item.label}<code>{item.code}</code></span>\n </Checkbox>\n <Tag className=\"token-permission-kind\">{TOKEN_PERMISSION_KIND_LABELS[item.kind]}</Tag>\n </div>)}\n </fieldset>)}\n {!groups.length && <p>{permissions.length ? '没有匹配的权限,已选项仍然保留。' : '当前没有可授予的权限。'}</p>}\n </div>\n {value.some(code => !permissions.includes(code)) && <Banner type=\"warning\" description=\"部分已选权限当前不可授予,请清空并重新选择。\"/>}\n <TokenPermissionPreview permissions={value}/>\n </div>;\n}\n\nexport const FormTokenPermissionPicker = withField(TokenPermissionPicker);\n","import { useEffect, useState } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { Plus, Copy, CheckCircle } from 'lucide-react';\nimport type { UserApiToken, UserApiTokenCreated } from '@fudanda/shared/identity';\nimport { useAuth } from '@fudanda/react-core/hooks/useAuth';\nimport { usePagination } from '@fudanda/react-core/hooks/usePagination';\nimport { abortSubmit } from '@fudanda/react-core/lib/abort-submit';\nimport { useSaveApiToken, useApiTokenDetail, useApiTokenSecret, useDeleteApiToken, useProfileApiTokens, useApiKeyPermissions } from '@fudanda/react-core/hooks/queries/profile';\nimport { Form, Button, Typography, Toast, Spin, Modal, Banner } from '@/ui';\nimport ConfigurableTable from '@/components/ConfigurableTable';\nimport { EditFormModal } from '@/components/EditFormModal';\nimport { listTableProps, useCrudOperationColumn } from '@/components/list-page';\nimport { useEditModal } from '@/hooks/useEditModal';\nimport { copyText } from '@/utils/clipboard';\nimport { createdAtColumn, dateTimeColumn } from '@/utils/table-columns';\nimport { FormTokenPermissionPicker, TokenPermissionDetails, TokenPermissionSummary } from './TokenPermissionPicker';\nimport './ApiTokensPage.css';\n\nconst { Text } = Typography;\n\nexport default function ApiTokensPage() {\n const { user } = useAuth();\n const ownerId = user!.id;\n const active = useLocation().pathname === '/system/api-tokens';\n const [scopeToken, setScopeToken] = useState<UserApiToken | null>(null);\n const tokenSecret = useApiTokenSecret(ownerId, active);\n const createdToken = tokenSecret.value;\n const [tokenCopied, setTokenCopied] = useState(false);\n const apiTokensQuery = useProfileApiTokens(active);\n const tokenPagination = usePagination({ resetKey: ownerId });\n const keyPermissionsQuery = useApiKeyPermissions(active);\n const saveTokenMutation = useSaveApiToken(ownerId, active);\n const deleteTokenMutation = useDeleteApiToken();\n // Secret responses stay in the open dialog, outside shared query caches.\n const tokenModal = useEditModal<UserApiToken | UserApiTokenCreated, {\n name: string;\n expiresAt?: Date | string | null;\n permissions?: string[];\n }, {\n name: string;\n expiresAt?: string;\n permissions: string[];\n }>({\n save: {\n mutateAsync: ({ id, values }) => saveTokenMutation.mutateAsync({ id, values }),\n isPending: saveTokenMutation.isPending,\n },\n useDetail: useApiTokenDetail,\n toValues: (record) => ({ name: record.name, expiresAt: 'expiresAt' in record ? record.expiresAt : undefined, permissions: 'permissions' in record ? record.permissions : [] }),\n beforeSave: (values) => {\n const name = values.name.trim();\n if (!name) {\n Toast.error('请填写 API Key 名称');\n abortSubmit('validation');\n }\n if (!values.permissions?.length) {\n Toast.error('请选择 API Key 权限');\n abortSubmit('validation');\n }\n return { name, ...(values.expiresAt ? { expiresAt: new Date(values.expiresAt).toISOString() } : {}), ...({ permissions: values.permissions }) };\n },\n defaults: { name: '', permissions: [] },\n successMessage: ({ isEdit }) => isEdit ? 'API Key 已更新' : null,\n onSaved: (saved) => { if (saved && 'token' in saved) { setTokenCopied(false); tokenSecret.showCreated(saved); } },\n });\n const closeEditor = tokenModal.close;\n useEffect(() => {\n closeEditor();\n setScopeToken(null);\n setTokenCopied(false);\n }, [active, ownerId, closeEditor]);\n async function handleDeleteToken(id: number) {\n await deleteTokenMutation.mutateAsync({ params: { id } });\n Toast.success('API Key 已撤销');\n }\n function copyToken(token: string) {\n void copyText(token).then((ok) => {\n if (!ok) {\n Toast.error('复制失败,请手动复制');\n return;\n }\n setTokenCopied(true);\n setTimeout(() => setTokenCopied(false), 2000);\n });\n }\n const tokenOperationColumn = useCrudOperationColumn<UserApiToken>({\n edit: (record) => tokenModal.openEdit(record),\n remove: (record) => handleDeleteToken(record.id),\n title: '确定要撤销该 API Key 吗?',\n content: '撤销后将无法恢复,使用该 API Key 的调用将立即失效。',\n successMessage: null,\n removeLabel: '撤销',\n width: 200,\n extra: (record) => [{ key: 'view', label: '查看 API Key', disabled: !record.canReveal,\n onClick: () => { setTokenCopied(false); void tokenSecret.reveal(record.id); } }],\n });\n return <div className=\"page-container page-container--stretch\">\n <Text type=\"tertiary\" size=\"small\" style={{ display: 'block' }}>\n API Key 可通过 <code>{'Authorization: Bearer <API_KEY>'}</code> 头访问 API,每人最多 20 个。\n </Text>\n <ConfigurableTable<UserApiToken> {...listTableProps(apiTokensQuery, { pagination: tokenPagination.buildPagination })}\n headerTitle=\"API Key\"\n toolBarRender={() => [<Button key=\"create\" type=\"primary\" icon={<Plus size={14}/>} onClick={tokenModal.openCreate}>新建 API Key</Button>]}\n columns={[\n { title: '名称', dataIndex: 'name', minWidth: 150, render: (v: string) => <Text strong>{v}</Text> },\n { title: '权限范围', dataIndex: 'permissions', width: 260, render: (permissions: string[], token: UserApiToken) => <TokenPermissionSummary permissions={permissions} onDetails={() => setScopeToken(token)}/> },\n { title: 'API Key 前缀', dataIndex: 'tokenPrefix', width: 180, render: (v: string, record: UserApiToken) => <div><code style={{ fontSize: 12 }}>{v}</code>{!record.canReveal && <div><Text type=\"tertiary\" size=\"small\">仅存摘要,无法查看原文</Text></div>}</div> },\n dateTimeColumn<NonNullable<typeof apiTokensQuery.data>[number]>('最后使用', 'lastUsedAt', { empty: '未使用' }),\n dateTimeColumn<NonNullable<typeof apiTokensQuery.data>[number]>('过期时间', 'expiresAt', { empty: '永久有效' }),\n createdAtColumn,\n tokenOperationColumn,\n ]}/>\n {/* ── 新建 API Key Modal ──────────────────────────────────────────────────────────────── */}\n {active && <EditFormModal modal={tokenModal} title={tokenModal.isEdit ? '编辑 API Key' : '新建 API Key'} okText={tokenModal.isEdit ? '保存' : '创建'} cancelText=\"取消\" width={740} centered formProps={{ labelPosition: 'top' }} okButtonProps={{ ...tokenModal.modalProps.okButtonProps, disabled: tokenModal.detailLoading || keyPermissionsQuery.isPending || Boolean(keyPermissionsQuery.error) }}>\n <Form.Input field=\"name\" maxLength={64} label=\"名称\" placeholder=\"如:本地开发、CI/CD 环境\" rules={[{ required: true, message: '请填写 API Key 名称' }]} style={{ width: '100%' }}/>\n {keyPermissionsQuery.error && <Banner type=\"danger\" description={<span>权限范围加载失败。<Button theme=\"borderless\" onClick={() => void keyPermissionsQuery.refetch()}>重试</Button></span>}/>}\n <FormTokenPermissionPicker field=\"permissions\" label=\"权限范围\" permissions={keyPermissionsQuery.data ?? []} disabled={keyPermissionsQuery.isPending || Boolean(keyPermissionsQuery.error)} rules={[{ validator: (_rule, value) => Array.isArray(value) && value.length > 0, message: '请选择至少一项权限' }]} extraText=\"API Key 权限不会超过账号当前权限;权限撤销、停用和改密后立即失效。\"/>\n <Form.DatePicker field=\"expiresAt\" label=\"过期时间\" type=\"dateTime\" placeholder=\"不填则永久有效\" style={{ width: '100%' }} disabledDate={(date) => !!date && date < new Date(new Date().setHours(0, 0, 0, 0))}/>\n </EditFormModal>}\n\n <Modal title={scopeToken ? `API Key 权限范围 · ${scopeToken.name}` : 'API Key 权限范围'} visible={active && !!scopeToken} onCancel={() => setScopeToken(null)} footer={<Button onClick={() => setScopeToken(null)}>关闭</Button>} width={740} centered>\n {scopeToken && <TokenPermissionDetails permissions={scopeToken.permissions}/>}\n </Modal>\n\n {/* ── 创建成功展示完整 API Key ──────────────────────────────────────────── */}\n <Modal title={tokenSecret.created ? 'API Key 创建成功' : '查看 API Key'} visible={active && (!!createdToken || tokenSecret.pending)} closeOnEsc onCancel={tokenSecret.close} footer={<Button type=\"primary\" onClick={tokenSecret.close}>关闭</Button>} width={520} centered>\n <Text type=\"warning\" style={{ display: 'block', marginBottom: 12, padding: '8px 12px', background: 'var(--arc-antd-color-warning-light-default)', borderRadius: 'var(--arc-antd-border-radius-medium)' }}>\n {createdToken?.canReveal ? '请妥善保管此 API Key,可在列表中再次查看或复制。' : '请立即复制并安全保存此 API Key,关闭后将无法再次查看完整内容。'}\n </Text>\n {tokenSecret.pending && <Spin />}\n {createdToken && (<div className=\"token-display\">\n <code style={{ flex: 1, wordBreak: 'break-all', fontSize: 12, lineHeight: 1.6 }}>{createdToken.token}</code>\n <Button icon={tokenCopied ? <CheckCircle size={14}/> : <Copy size={14}/>} type={tokenCopied ? 'tertiary' : 'primary'} onClick={() => copyToken(createdToken.token)} style={{ flexShrink: 0 }}>\n {tokenCopied ? '已复制' : '复制'}\n </Button>\n </div>)}\n </Modal>\n </div>;\n}\n"]}
|