@hotmeshio/long-tail 0.8.3 → 0.8.4
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/build/api/escalations/create.js +19 -60
- package/build/api/escalations/resolve.js +12 -4
- package/build/api/escalations/single.js +8 -4
- package/build/api/roles.d.ts +1 -0
- package/build/scripts/twin-farm.d.ts +12 -13
- package/build/scripts/twin-farm.js +61 -75
- package/build/services/escalation/queries.d.ts +13 -0
- package/build/services/escalation/queries.js +27 -0
- package/build/services/orchestrator/condition.d.ts +18 -12
- package/build/services/orchestrator/condition.js +11 -8
- package/build/services/role/index.d.ts +1 -2
- package/build/services/role/index.js +1 -2
- package/build/services/role/schema-validator.d.ts +9 -0
- package/build/services/role/schema-validator.js +42 -0
- package/build/services/role/sql.d.ts +1 -1
- package/build/services/role/sql.js +2 -2
- package/build/services/role/types.d.ts +8 -6
- package/build/system/mcp-servers/admin/schemas.js +4 -2
- package/build/system/mcp-servers/human-queue-schemas.js +6 -2
- package/build/system/mcp-servers/human-queue.js +11 -3
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/config.d.ts +2 -0
- package/build/types/startup.d.ts +5 -1
- package/dashboard/dist/assets/{AdminDashboard-Dhr7sUq6.js → AdminDashboard-B-JptT54.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-Dhr7sUq6.js.map → AdminDashboard-B-JptT54.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-CUPm8FjH.js → AgentConfigPage-B1Jc6iJk.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-CUPm8FjH.js.map → AgentConfigPage-B1Jc6iJk.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-C9Tmmhhc.js → AgentDetailPage-CWpclCOY.js} +2 -2
- package/dashboard/dist/assets/{AgentDetailPage-C9Tmmhhc.js.map → AgentDetailPage-CWpclCOY.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-Pj47ZJ2U.js → AgentsPage-DyAf5GA2.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-Pj47ZJ2U.js.map → AgentsPage-DyAf5GA2.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-BxakNqha.js → AvailableEscalationsPage-DDwAgklw.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-BxakNqha.js.map → AvailableEscalationsPage-DDwAgklw.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-CCIo5ic0.js → BotPicker-B1RdaNuY.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-CCIo5ic0.js.map → BotPicker-B1RdaNuY.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-XFVq4iPX.js → CapabilitiesPage-CxHDnyjX.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-XFVq4iPX.js.map → CapabilitiesPage-CxHDnyjX.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-CBKICsCu.js → CollapsibleSection-Ds0e8cCO.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-CBKICsCu.js.map → CollapsibleSection-Ds0e8cCO.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-BN_d7ybc.js → CredentialsPage-D8UVO-3A.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-BN_d7ybc.js.map → CredentialsPage-D8UVO-3A.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-4V_EXMUg.js → CronLabel-ZesYXxCH.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-4V_EXMUg.js.map → CronLabel-ZesYXxCH.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-BdurQj-B.js → CustomDurationPicker-OKlwH5a_.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-BdurQj-B.js.map → CustomDurationPicker-OKlwH5a_.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-CO8XMSJX.js → ElapsedCell-CO8S6vdb.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-CO8XMSJX.js.map → ElapsedCell-CO8S6vdb.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-hzFtuyha.js → EscalationSchemaPage-Br5sD8-N.js} +2 -2
- package/dashboard/dist/assets/{EscalationSchemaPage-hzFtuyha.js.map → EscalationSchemaPage-Br5sD8-N.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-qlo0mxxa.js → EscalationsOverview-DMpRvVql.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-qlo0mxxa.js.map → EscalationsOverview-DMpRvVql.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-D9RjAT_a.js → EventTable-BARJeiS2.js} +2 -2
- package/dashboard/dist/assets/{EventTable-D9RjAT_a.js.map → EventTable-BARJeiS2.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-CU3r2tzN.js → GraphInvokePage-CTuul-av.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-CU3r2tzN.js.map → GraphInvokePage-CTuul-av.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-B7pb4-Gx.js → HomePage-BKFpOaHX.js} +2 -2
- package/dashboard/dist/assets/{HomePage-B7pb4-Gx.js.map → HomePage-BKFpOaHX.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-C_64Y22Z.js → ListToolbar-Dz2_neVF.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-C_64Y22Z.js.map → ListToolbar-Dz2_neVF.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-D-4eSOTc.js → McpOverview-Do-vaEqV.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-D-4eSOTc.js.map → McpOverview-Do-vaEqV.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-BYwDb8LC.js → McpQueryDetailPage-HwDGNSbN.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-BYwDb8LC.js.map → McpQueryDetailPage-HwDGNSbN.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-CIijB5t2.js → McpQueryPage-DxMUpQ7R.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-CIijB5t2.js.map → McpQueryPage-DxMUpQ7R.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-CQmhfgju.js → McpRunDetailPage-BzzZIXIk.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-CQmhfgju.js.map → McpRunDetailPage-BzzZIXIk.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-CdDyeOdi.js → McpRunsPage-D3J42d2i.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-CdDyeOdi.js.map → McpRunsPage-D3J42d2i.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-Cz_0K8tj.js → OperationsPage-BaM-QDhy.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-Cz_0K8tj.js.map → OperationsPage-BaM-QDhy.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-DFORmS46.js → OperatorDashboard-BqJn8wEZ.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-DFORmS46.js.map → OperatorDashboard-BqJn8wEZ.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-DwypVFE2.js → ProcessDetailPage-C8sT2xuE.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-DwypVFE2.js.map → ProcessDetailPage-C8sT2xuE.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-tNLvALwT.js → ProcessesListPage-eA8buUgd.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-tNLvALwT.js.map → ProcessesListPage-eA8buUgd.js.map} +1 -1
- package/dashboard/dist/assets/{RoleDetailPage-BPsrUqIa.js → RoleDetailPage-aR-ror5v.js} +2 -2
- package/dashboard/dist/assets/{RoleDetailPage-BPsrUqIa.js.map → RoleDetailPage-aR-ror5v.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-txueySPI.js → RolesPage-BQNQxsMY.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-txueySPI.js.map → RolesPage-BQNQxsMY.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-Bvefon9B.js → RunAsSelector-mhusrlYE.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-Bvefon9B.js.map → RunAsSelector-mhusrlYE.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-CeQCzVIA.js → StickyPagination-CqT9Q1I6.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-CeQCzVIA.js.map → StickyPagination-CqT9Q1I6.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-6wEm6o6t.js → StreamMessageDetail-jOJaoupp.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-6wEm6o6t.js.map → StreamMessageDetail-jOJaoupp.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-C97Rldf5.js → SwimlaneTimeline-BrfmWgAj.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-C97Rldf5.js.map → SwimlaneTimeline-BrfmWgAj.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-B09mLOCE.js → TaskDetailPage-Cus_JHIC.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-B09mLOCE.js.map → TaskDetailPage-Cus_JHIC.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CQhiSGkN.js → TasksListPage-B7GK8AoX.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CQhiSGkN.js.map → TasksListPage-B7GK8AoX.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-BkyeBcMF.js → TimeAgo-C606LzT3.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-BkyeBcMF.js.map → TimeAgo-C606LzT3.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-DVp_UdEB.js → TimestampCell-hfh6zvH-.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-DVp_UdEB.js.map → TimestampCell-hfh6zvH-.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-CZOuRP_i.js → ToolTestPanel-CsPsyvQq.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-CZOuRP_i.js.map → ToolTestPanel-CsPsyvQq.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-0mvQde8R.js → TopicDetailPage-Diz6r7zr.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-0mvQde8R.js.map → TopicDetailPage-Diz6r7zr.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-DkvsHLLe.js → TopicsPage-B6fn7fFh.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-DkvsHLLe.js.map → TopicsPage-B6fn7fFh.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-EaD_Tz9y.js → UserName-Cc-5QH5q.js} +2 -2
- package/dashboard/dist/assets/{UserName-EaD_Tz9y.js.map → UserName-Cc-5QH5q.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-CjMSQ9Bb.js → WorkflowExecutionPage-BFq7UdhA.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-CjMSQ9Bb.js.map → WorkflowExecutionPage-BFq7UdhA.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-BgUz_jO6.js → WorkflowsDashboard-CHCM6hUa.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-BgUz_jO6.js.map → WorkflowsDashboard-CHCM6hUa.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-BzUjUfAz.js → WorkflowsOverview-WeOvl8-_.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-BzUjUfAz.js.map → WorkflowsOverview-WeOvl8-_.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-C48Ui513.js → YamlWorkflowDetailPage-6GfhVDpv.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-C48Ui513.js.map → YamlWorkflowDetailPage-6GfhVDpv.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-CQ-dk84N.js → YamlWorkflowsPage-DqcY3ocP.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-CQ-dk84N.js.map → YamlWorkflowsPage-DqcY3ocP.js.map} +1 -1
- package/dashboard/dist/assets/{agents-O1GlQE9p.js → agents-DlzvjNxE.js} +2 -2
- package/dashboard/dist/assets/{agents-O1GlQE9p.js.map → agents-DlzvjNxE.js.map} +1 -1
- package/dashboard/dist/assets/{bots-DB5Z7MEk.js → bots-CWMN-KUI.js} +2 -2
- package/dashboard/dist/assets/{bots-DB5Z7MEk.js.map → bots-CWMN-KUI.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-Du9EfNdT.js → capabilities-_WSZ7cxO.js} +2 -2
- package/dashboard/dist/assets/{capabilities-Du9EfNdT.js.map → capabilities-_WSZ7cxO.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-ku4V2nVk.js → controlplane-_k9nWZy3.js} +2 -2
- package/dashboard/dist/assets/{controlplane-ku4V2nVk.js.map → controlplane-_k9nWZy3.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-oVVz7Lw2.js → escalation-CK8ElYzD.js} +2 -2
- package/dashboard/dist/assets/{escalation-oVVz7Lw2.js.map → escalation-CK8ElYzD.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-C-xaR_Qg.js → escalation-columns-Dyrf6Tdp.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-C-xaR_Qg.js.map → escalation-columns-Dyrf6Tdp.js.map} +1 -1
- package/dashboard/dist/assets/{index-DsKK1fCc.js → index-BiApvBEz.js} +2 -2
- package/dashboard/dist/assets/{index-DsKK1fCc.js.map → index-BiApvBEz.js.map} +1 -1
- package/dashboard/dist/assets/{index-61yKjTkk.js → index-C3h0qGzG.js} +2 -2
- package/dashboard/dist/assets/{index-61yKjTkk.js.map → index-C3h0qGzG.js.map} +1 -1
- package/dashboard/dist/assets/{index-CxlsLEr1.js → index-C5Yc3TT7.js} +2 -2
- package/dashboard/dist/assets/{index-CxlsLEr1.js.map → index-C5Yc3TT7.js.map} +1 -1
- package/dashboard/dist/assets/{index-Bcgsf2yD.js → index-C7VXLKJs.js} +2 -2
- package/dashboard/dist/assets/{index-Bcgsf2yD.js.map → index-C7VXLKJs.js.map} +1 -1
- package/dashboard/dist/assets/{index-DkZnXWTA.js → index-D8GcHxNJ.js} +2 -2
- package/dashboard/dist/assets/{index-DkZnXWTA.js.map → index-D8GcHxNJ.js.map} +1 -1
- package/dashboard/dist/assets/{index-DcZDyLHC.js → index-Dc-Ye2wk.js} +2 -2
- package/dashboard/dist/assets/{index-DcZDyLHC.js.map → index-Dc-Ye2wk.js.map} +1 -1
- package/dashboard/dist/assets/{index-CyXilW90.js → index-Dd4Si1Rl.js} +2 -2
- package/dashboard/dist/assets/{index-CyXilW90.js.map → index-Dd4Si1Rl.js.map} +1 -1
- package/dashboard/dist/assets/{index-MbEPoyTe.js → index-DwWP-Z_c.js} +3 -3
- package/dashboard/dist/assets/{index-MbEPoyTe.js.map → index-DwWP-Z_c.js.map} +1 -1
- package/dashboard/dist/assets/index-Ex5tEte8.js +5 -0
- package/dashboard/dist/assets/index-Ex5tEte8.js.map +1 -0
- package/dashboard/dist/assets/index-OV1JoB_P.js +6 -0
- package/dashboard/dist/assets/index-OV1JoB_P.js.map +1 -0
- package/dashboard/dist/assets/{index-BwXtXaw8.js → index-ZBj6Xgim.js} +2 -2
- package/dashboard/dist/assets/{index-BwXtXaw8.js.map → index-ZBj6Xgim.js.map} +1 -1
- package/dashboard/dist/assets/{index-DgAmkmtv.js → index-kKufOPLo.js} +2 -2
- package/dashboard/dist/assets/{index-DgAmkmtv.js.map → index-kKufOPLo.js.map} +1 -1
- package/dashboard/dist/assets/{index-aHhMmZ0W.js → index-uUYXmvFf.js} +2 -2
- package/dashboard/dist/assets/{index-aHhMmZ0W.js.map → index-uUYXmvFf.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-CTjJVvIG.js → knowledge-fYoEF4Lx.js} +2 -2
- package/dashboard/dist/assets/{knowledge-CTjJVvIG.js.map → knowledge-fYoEF4Lx.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-CsHkygRS.js → mcp-1lzlgtS8.js} +2 -2
- package/dashboard/dist/assets/{mcp-CsHkygRS.js.map → mcp-1lzlgtS8.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-BCt4tpjO.js → mcp-query-nlrAz7m_.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-BCt4tpjO.js.map → mcp-query-nlrAz7m_.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-BpGmuS5V.js → pipelines-Ihi7EKXi.js} +2 -2
- package/dashboard/dist/assets/{pipelines-BpGmuS5V.js.map → pipelines-Ihi7EKXi.js.map} +1 -1
- package/dashboard/dist/assets/{roles-lHLgLwOY.js → roles-D4Wn7kE9.js} +2 -2
- package/dashboard/dist/assets/{roles-lHLgLwOY.js.map → roles-D4Wn7kE9.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-BHfimh-E.js → tasks-Crk9Y3C4.js} +2 -2
- package/dashboard/dist/assets/{tasks-BHfimh-E.js.map → tasks-Crk9Y3C4.js.map} +1 -1
- package/dashboard/dist/assets/{topics-BW2cS79q.js → topics-CtfcCyw9.js} +2 -2
- package/dashboard/dist/assets/{topics-BW2cS79q.js.map → topics-CtfcCyw9.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-CeOIM1Ix.js → useEventHooks-Dn_vN2xE.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-CeOIM1Ix.js.map → useEventHooks-Dn_vN2xE.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-CEVLPGGY.js → useNamespace-Cfs3vKWk.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-CEVLPGGY.js.map → useNamespace-Cfs3vKWk.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-DdRNcy7s.js → useYamlActivityEvents-ymobxH47.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-DdRNcy7s.js.map → useYamlActivityEvents-ymobxH47.js.map} +1 -1
- package/dashboard/dist/assets/{users-CAih5Fty.js → users-DngGIiC_.js} +2 -2
- package/dashboard/dist/assets/{users-CAih5Fty.js.map → users-DngGIiC_.js.map} +1 -1
- package/dashboard/dist/assets/{workflows-C_gCwB9q.js → workflows-DuUspMAl.js} +2 -2
- package/dashboard/dist/assets/{workflows-C_gCwB9q.js.map → workflows-DuUspMAl.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-CPabf8Sf.js → yaml-workflows-DXQCiOsP.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-CPabf8Sf.js.map → yaml-workflows-DXQCiOsP.js.map} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/docs/api/http/escalations.md +8 -4
- package/docs/api/http/roles.md +1 -1
- package/docs/api/http/workflows.md +1 -1
- package/docs/api/sdk/escalations.md +3 -3
- package/docs/api/sdk/workflows.md +1 -1
- package/docs/dashboard.md +2 -2
- package/docs/data.md +1 -1
- package/docs/hitl-guide.md +2 -3
- package/package.json +1 -1
- package/dashboard/dist/assets/index-CAzFU1rn.js +0 -9
- package/dashboard/dist/assets/index-CAzFU1rn.js.map +0 -1
- package/dashboard/dist/assets/index-D0bDVU2a.js +0 -6
- package/dashboard/dist/assets/index-D0bDVU2a.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-61yKjTkk.js","sources":["../../src/components/common/layout/StepIndicator.tsx","../../src/pages/mcp/servers/detail/server-form-types.ts","../../src/pages/mcp/servers/detail/TransportStep.tsx","../../src/pages/mcp/servers/detail/DiscoveryStep.tsx","../../src/pages/mcp/servers/detail/TestStep.tsx","../../src/pages/mcp/servers/detail/ReviewStep.tsx","../../src/pages/mcp/servers/detail/McpServerDetailPage.tsx"],"sourcesContent":["interface StepIndicatorProps {\n steps: string[];\n currentStep: number;\n onStepClick?: (step: number) => void;\n}\n\nexport function StepIndicator({ steps, currentStep, onStepClick }: StepIndicatorProps) {\n return (\n <div className=\"flex items-center justify-center gap-1 pb-4 border-b border-surface-border mb-4\">\n {steps.map((label, i) => {\n const done = i < currentStep;\n const active = i === currentStep;\n const clickable = !!onStepClick;\n return (\n <div key={label} className=\"flex items-center gap-1\">\n {i > 0 && (\n <div className={`w-4 h-px ${done ? 'bg-accent' : 'bg-surface-border'}`} />\n )}\n <button\n type=\"button\"\n onClick={clickable ? () => onStepClick(i) : undefined}\n className={`flex items-center gap-1 ${clickable ? 'cursor-pointer' : 'cursor-default'}`}\n >\n <span\n className={`w-5 h-5 rounded-full text-[10px] font-semibold flex items-center justify-center shrink-0 transition-colors ${\n active\n ? 'bg-accent text-text-inverse'\n : done\n ? 'bg-accent-muted text-accent'\n : 'bg-surface-sunken text-text-tertiary'\n } ${clickable && !active ? 'hover:bg-accent-muted hover:text-accent' : ''}`}\n >\n {i + 1}\n </span>\n <span\n className={`text-[10px] font-semibold uppercase tracking-wider whitespace-nowrap transition-colors ${\n active ? 'text-text-primary' : 'text-text-tertiary'\n } ${clickable && !active ? 'hover:text-text-primary' : ''}`}\n >\n {label}\n </span>\n </button>\n </div>\n );\n })}\n </div>\n );\n}\n","import type { McpServerRecord, McpToolManifest } from '../../../../api/types';\n\nexport interface ServerFormState {\n name: string;\n description: string;\n mode: 'in-process' | 'network' | 'local-process';\n transport_type: 'stdio' | 'sse' | 'streamable-http';\n // stdio fields\n command: string;\n args: string;\n env_vars: string;\n // network fields\n url: string;\n // shared\n auto_connect: boolean;\n tags: string[];\n compile_hints: string;\n credential_providers: string[];\n discovered_tools: McpToolManifest[] | null;\n}\n\nexport const EMPTY_FORM: ServerFormState = {\n name: '',\n description: '',\n mode: 'network',\n transport_type: 'sse',\n command: '',\n args: '',\n env_vars: '{}',\n url: '',\n auto_connect: false,\n tags: [],\n compile_hints: '',\n credential_providers: [],\n discovered_tools: null,\n};\n\nexport function serverToForm(s: McpServerRecord): ServerFormState {\n const config = s.transport_config ?? {};\n const isBuiltin = !!(config as any).builtin;\n\n let mode: ServerFormState['mode'] = 'network';\n if (isBuiltin) mode = 'in-process';\n else if (s.transport_type === 'stdio') mode = 'local-process';\n\n return {\n name: s.name,\n description: s.description ?? '',\n mode,\n transport_type: s.transport_type,\n command: (config as any).command ?? '',\n args: ((config as any).args ?? []).join(', '),\n env_vars: (config as any).env ? JSON.stringify((config as any).env, null, 2) : '{}',\n url: (config as any).url ?? '',\n auto_connect: s.auto_connect,\n tags: s.tags ?? [],\n compile_hints: (s as any).compile_hints ?? '',\n credential_providers: s.credential_providers ?? [],\n discovered_tools: s.tool_manifest ?? null,\n };\n}\n\nexport function formToPayload(form: ServerFormState) {\n let transport_config: Record<string, unknown> = {};\n\n if (form.mode === 'local-process') {\n transport_config = {\n command: form.command.trim(),\n args: form.args.split(',').map((a) => a.trim()).filter(Boolean),\n env: form.env_vars.trim() ? JSON.parse(form.env_vars) : undefined,\n };\n } else if (form.mode === 'network') {\n transport_config = { url: form.url.trim() };\n }\n // in-process: transport_config stays empty (server manages it)\n\n return {\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n transport_type: form.mode === 'local-process' ? 'stdio' as const : form.transport_type,\n transport_config,\n auto_connect: form.auto_connect,\n tags: form.tags,\n compile_hints: form.compile_hints.trim() || undefined,\n credential_providers: form.credential_providers.length > 0 ? form.credential_providers : undefined,\n };\n}\n\nexport const STEP_LABELS = ['Transport', 'Discovery', 'Test', 'Review'];\n\nexport function isStepValid(step: number, form: ServerFormState): boolean {\n if (step === 1) {\n if (!form.name.trim()) return false;\n if (form.mode === 'network' && !form.url.trim()) return false;\n if (form.mode === 'local-process' && !form.command.trim()) return false;\n return true;\n }\n return true;\n}\n\nexport const labelCls = 'label';\nexport const hintCls = 'hint';\n","import type { ServerFormState } from './server-form-types';\nimport { labelCls, hintCls } from './server-form-types';\n\ninterface Props {\n form: ServerFormState;\n set: (field: keyof ServerFormState, value: any) => void;\n isBuiltin: boolean;\n}\n\nconst modes = [\n { value: 'in-process', label: 'In-Process', hint: 'Built-in server running inside the app' },\n { value: 'network', label: 'Network Service', hint: 'Remote server via SSE or Streamable HTTP' },\n { value: 'local-process', label: 'Local Process', hint: 'Spawn a local command via stdio' },\n] as const;\n\nexport function TransportStep({ form, set, isBuiltin }: Props) {\n return (\n <div className=\"space-y-5\">\n {/* Mode selector */}\n <div>\n <label className={labelCls}>Connection Mode</label>\n <div className=\"grid grid-cols-3 gap-3 mt-1\">\n {modes.map((m) => {\n const active = form.mode === m.value;\n const disabled = isBuiltin && m.value !== 'in-process';\n return (\n <button\n key={m.value}\n type=\"button\"\n disabled={disabled}\n onClick={() => {\n set('mode', m.value);\n if (m.value === 'local-process') set('transport_type', 'stdio');\n if (m.value === 'network') set('transport_type', 'sse');\n }}\n className={`text-left p-3 rounded-md border transition-colors ${\n active\n ? 'border-accent bg-accent/5'\n : disabled\n ? 'border-surface-border bg-surface-sunken opacity-50 cursor-not-allowed'\n : 'border-surface-border hover:border-text-tertiary cursor-pointer'\n }`}\n >\n <span className={`text-xs font-medium ${active ? 'text-accent' : 'text-text-primary'}`}>\n {m.label}\n </span>\n <span className=\"block text-[10px] text-text-tertiary mt-0.5\">{m.hint}</span>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Name + Description (always shown) */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className={labelCls}>Name</label>\n <input\n type=\"text\"\n value={form.name}\n onChange={(e) => set('name', e.target.value)}\n placeholder=\"e.g., vision-server\"\n className=\"input text-xs w-full\"\n disabled={isBuiltin}\n />\n </div>\n <div>\n <label className={labelCls}>Description</label>\n <input\n type=\"text\"\n value={form.description}\n onChange={(e) => set('description', e.target.value)}\n placeholder=\"Optional description\"\n className=\"input text-xs w-full\"\n />\n </div>\n </div>\n\n {/* In-Process: read-only info */}\n {form.mode === 'in-process' && (\n <div>\n <p className={hintCls}>\n This server runs in-process via InMemoryTransport. Transport is managed automatically — no configuration needed.\n </p>\n </div>\n )}\n\n {/* Network: URL + transport toggle */}\n {form.mode === 'network' && (\n <>\n <div>\n <label className={labelCls}>Server URL</label>\n <input\n type=\"text\"\n value={form.url}\n onChange={(e) => set('url', e.target.value)}\n placeholder=\"https://mcp-server.example.com/sse\"\n className=\"input text-xs w-full font-mono\"\n />\n </div>\n <div>\n <label className={labelCls}>Transport Protocol</label>\n <div className=\"flex gap-2 mt-1\">\n {(['sse', 'streamable-http'] as const).map((t) => (\n <button\n key={t}\n type=\"button\"\n onClick={() => set('transport_type', t)}\n className={`px-3 py-1.5 text-xs rounded-md border transition-colors ${\n form.transport_type === t\n ? 'border-accent bg-accent/5 text-accent font-medium'\n : 'border-surface-border text-text-secondary hover:border-text-tertiary'\n }`}\n >\n {t === 'sse' ? 'SSE' : 'Streamable HTTP'}\n </button>\n ))}\n </div>\n </div>\n </>\n )}\n\n {/* Local Process: command + args + env */}\n {form.mode === 'local-process' && (\n <>\n <div>\n <label className={labelCls}>Command</label>\n <input\n type=\"text\"\n value={form.command}\n onChange={(e) => set('command', e.target.value)}\n placeholder=\"e.g., npx\"\n className=\"input text-xs w-full font-mono\"\n />\n </div>\n <div>\n <label className={labelCls}>Arguments (comma-separated)</label>\n <input\n type=\"text\"\n value={form.args}\n onChange={(e) => set('args', e.target.value)}\n placeholder=\"e.g., -y, @modelcontextprotocol/server-filesystem, /tmp\"\n className=\"input text-xs w-full font-mono\"\n />\n </div>\n <div>\n <label className={labelCls}>Environment Variables (JSON)</label>\n <textarea\n value={form.env_vars}\n onChange={(e) => set('env_vars', e.target.value)}\n className=\"input-json w-full\"\n rows={3}\n spellCheck={false}\n />\n </div>\n </>\n )}\n\n {/* Auto-connect */}\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={form.auto_connect}\n onChange={(e) => set('auto_connect', e.target.checked)}\n className=\"w-4 h-4 rounded border-border accent-accent\"\n />\n <span className=\"text-xs text-text-primary\">Auto-connect on startup</span>\n </label>\n </div>\n );\n}\n","import { useState, type KeyboardEvent } from 'react';\nimport { X } from 'lucide-react';\nimport { TagInput } from '../../../../components/common/form/TagInput';\nimport type { ServerFormState } from './server-form-types';\nimport { labelCls, hintCls } from './server-form-types';\n\ninterface Props {\n form: ServerFormState;\n set: (field: keyof ServerFormState, value: any) => void;\n}\n\nexport function DiscoveryStep({ form, set }: Props) {\n const [cpInput, setCpInput] = useState('');\n\n const addProvider = (raw: string) => {\n const v = raw.trim().toLowerCase();\n if (v && !form.credential_providers.includes(v)) {\n set('credential_providers', [...form.credential_providers, v]);\n }\n setCpInput('');\n };\n\n const removeProvider = (p: string) => {\n set('credential_providers', form.credential_providers.filter((x) => x !== p));\n };\n\n const handleCpKey = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter' || e.key === ',') {\n e.preventDefault();\n addProvider(cpInput);\n } else if (e.key === 'Backspace' && !cpInput && form.credential_providers.length > 0) {\n removeProvider(form.credential_providers[form.credential_providers.length - 1]);\n }\n };\n\n return (\n <div className=\"space-y-5\">\n {/* Tags */}\n <div>\n <label className={labelCls}>Tags</label>\n <TagInput\n tags={form.tags}\n onChange={(tags) => set('tags', tags)}\n placeholder=\"Add tag (e.g., database, analytics)...\"\n />\n <p className={hintCls}>\n Tags enable tool discovery. Workflows filter available MCP servers by tags to find relevant tools.\n </p>\n </div>\n\n {/* Compile Hints */}\n <div>\n <label className={labelCls}>Compile Hints</label>\n <textarea\n value={form.compile_hints}\n onChange={(e) => set('compile_hints', e.target.value)}\n placeholder=\"Guidance for the workflow compiler when generating YAML from this server's tools...\"\n className=\"input text-xs w-full leading-relaxed\"\n rows={4}\n spellCheck={false}\n />\n <p className={hintCls}>\n Free-form text that guides the workflow compiler. Describe how tools should be composed, sequenced, or parameterized.\n </p>\n </div>\n\n {/* Credential Providers */}\n <div>\n <label className={labelCls}>Credential Providers</label>\n <div className=\"flex flex-wrap items-center gap-1.5 bg-surface-sunken border border-surface-border rounded-md px-2 py-1.5 focus-within:ring-1 focus-within:ring-accent-primary\">\n {form.credential_providers.map((p) => (\n <span\n key={p}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-accent/10 text-accent text-[11px] font-medium\"\n >\n {p}\n <button\n type=\"button\"\n onClick={() => removeProvider(p)}\n className=\"hover:text-status-error transition-colors\"\n >\n <X className=\"w-2.5 h-2.5\" />\n </button>\n </span>\n ))}\n <input\n type=\"text\"\n value={cpInput}\n onChange={(e) => setCpInput(e.target.value)}\n onKeyDown={handleCpKey}\n onBlur={() => { if (cpInput.trim()) addProvider(cpInput); }}\n placeholder={form.credential_providers.length === 0 ? 'Add provider (e.g., github, slack)...' : ''}\n className=\"flex-1 min-w-[80px] bg-transparent text-xs text-text-primary outline-none placeholder:text-text-tertiary\"\n />\n </div>\n <p className={hintCls}>\n IAM credential providers required by this server's tools. Users will be prompted to connect these before tool execution.\n </p>\n </div>\n </div>\n );\n}\n","import { CheckCircle2, XCircle, Loader2 } from 'lucide-react';\nimport { useTestConnection } from '../../../../api/mcp';\nimport type { ServerFormState } from './server-form-types';\nimport { formToPayload } from './server-form-types';\nimport { hintCls } from './server-form-types';\n\ninterface Props {\n form: ServerFormState;\n set: (field: keyof ServerFormState, value: any) => void;\n}\n\nexport function TestStep({ form, set }: Props) {\n const test = useTestConnection();\n const isInProcess = form.mode === 'in-process';\n\n const handleTest = () => {\n const payload = formToPayload(form);\n test.mutate(\n { transport_type: payload.transport_type, transport_config: payload.transport_config },\n {\n onSuccess: (result) => {\n if (result.success) {\n set('discovered_tools', result.tools);\n }\n },\n },\n );\n };\n\n const result = test.data;\n const tools = form.discovered_tools ?? result?.tools ?? [];\n\n return (\n <div className=\"space-y-5\">\n {isInProcess ? (\n <div>\n <p className=\"text-sm text-text-secondary\">\n In-process servers connect lazily on first tool call. No connection test needed.\n </p>\n {form.discovered_tools && form.discovered_tools.length > 0 && (\n <div className=\"mt-4\">\n <p className=\"text-xs text-text-tertiary mb-2\">\n {form.discovered_tools.length} tool{form.discovered_tools.length !== 1 ? 's' : ''} cached from last connection\n </p>\n <ToolList tools={form.discovered_tools} />\n </div>\n )}\n </div>\n ) : (\n <>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={handleTest}\n disabled={test.isPending}\n className=\"btn-primary text-xs\"\n >\n {test.isPending ? (\n <span className=\"flex items-center gap-1.5\">\n <Loader2 className=\"w-3 h-3 animate-spin\" />\n Connecting...\n </span>\n ) : (\n 'Test Connection'\n )}\n </button>\n {result?.success && (\n <span className=\"flex items-center gap-1 text-xs text-status-success\">\n <CheckCircle2 className=\"w-3.5 h-3.5\" />\n Connected — {tools.length} tool{tools.length !== 1 ? 's' : ''} discovered\n </span>\n )}\n {result && !result.success && (\n <span className=\"flex items-center gap-1 text-xs text-status-error\">\n <XCircle className=\"w-3.5 h-3.5\" />\n {result.error || 'Connection failed'}\n </span>\n )}\n </div>\n\n {tools.length > 0 && (\n <div>\n <p className=\"text-xs text-text-tertiary mb-2\">Discovered tools</p>\n <ToolList tools={tools} />\n </div>\n )}\n\n <p className={hintCls}>\n Tests connectivity by connecting to the server and listing available tools. The server must be reachable from this machine.\n </p>\n </>\n )}\n </div>\n );\n}\n\nfunction ToolList({ tools }: { tools: { name: string; description?: string }[] }) {\n return (\n <div className=\"max-h-[280px] overflow-y-auto border border-surface-border rounded-md divide-y divide-surface-border\">\n {tools.map((t) => (\n <div key={t.name} className=\"px-3 py-2\">\n <span className=\"text-xs font-medium text-text-primary font-mono\">{t.name}</span>\n {t.description && (\n <span className=\"block text-[10px] text-text-tertiary mt-0.5 line-clamp-2\">{t.description}</span>\n )}\n </div>\n ))}\n </div>\n );\n}\n","import type { ServerFormState } from './server-form-types';\nimport { labelCls } from './server-form-types';\n\ninterface Props {\n form: ServerFormState;\n}\n\nconst modeLabels: Record<string, string> = {\n 'in-process': 'In-Process',\n 'network': 'Network Service',\n 'local-process': 'Local Process',\n};\n\nconst transportLabels: Record<string, string> = {\n stdio: 'stdio',\n sse: 'SSE',\n 'streamable-http': 'Streamable HTTP',\n};\n\nexport function ReviewStep({ form }: Props) {\n const tools = form.discovered_tools ?? [];\n\n return (\n <div className=\"space-y-4\">\n <Row label=\"Name\" value={form.name} />\n {form.description && <Row label=\"Description\" value={form.description} />}\n <Row label=\"Mode\" value={modeLabels[form.mode] ?? form.mode} />\n\n {form.mode === 'network' && (\n <>\n <Row label=\"Transport\" value={transportLabels[form.transport_type] ?? form.transport_type} />\n <Row label=\"URL\" value={form.url} mono />\n </>\n )}\n {form.mode === 'local-process' && (\n <>\n <Row label=\"Command\" value={form.command} mono />\n {form.args && <Row label=\"Args\" value={form.args} mono />}\n </>\n )}\n\n <Row label=\"Auto-connect\" value={form.auto_connect ? 'Yes' : 'No'} />\n\n {form.tags.length > 0 && (\n <div>\n <label className={labelCls}>Tags</label>\n <div className=\"flex flex-wrap gap-1.5 mt-1\">\n {form.tags.map((t) => (\n <span key={t} className=\"px-2 py-0.5 rounded-full bg-accent/10 text-accent text-[11px] font-medium\">\n {t}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {form.credential_providers.length > 0 && (\n <div>\n <label className={labelCls}>Credential Providers</label>\n <div className=\"flex flex-wrap gap-1.5 mt-1\">\n {form.credential_providers.map((p) => (\n <span key={p} className=\"px-2 py-0.5 rounded-full bg-accent/10 text-accent text-[11px] font-medium\">\n {p}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {form.compile_hints && <Row label=\"Compile Hints\" value={form.compile_hints} />}\n\n {tools.length > 0 && (\n <Row label=\"Discovered Tools\" value={`${tools.length} tool${tools.length !== 1 ? 's' : ''}`} />\n )}\n </div>\n );\n}\n\nfunction Row({ label, value, mono }: { label: string; value: string; mono?: boolean }) {\n return (\n <div>\n <label className={labelCls}>{label}</label>\n <p className={`text-xs text-text-primary mt-0.5 ${mono ? 'font-mono' : ''}`}>{value}</p>\n </div>\n );\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport { useParams, useNavigate, useSearchParams } from 'react-router-dom';\nimport { useMcpServer, useCreateMcpServer, useUpdateMcpServer } from '../../../../api/mcp';\nimport { StepIndicator } from '../../../../components/common/layout/StepIndicator';\nimport { PageHeader } from '../../../../components/common/layout/PageHeader';\nimport {\n EMPTY_FORM,\n serverToForm,\n formToPayload,\n STEP_LABELS,\n isStepValid,\n} from './server-form-types';\nimport type { ServerFormState } from './server-form-types';\nimport { TransportStep } from './TransportStep';\nimport { DiscoveryStep } from './DiscoveryStep';\nimport { TestStep } from './TestStep';\nimport { ReviewStep } from './ReviewStep';\n\nexport function McpServerDetailPage() {\n const { serverId } = useParams<{ serverId: string }>();\n const isNew = !serverId;\n const navigate = useNavigate();\n const { data: existing, isLoading } = useMcpServer(serverId ?? '');\n const createServer = useCreateMcpServer();\n const updateServer = useUpdateMcpServer();\n\n const [form, setForm] = useState<ServerFormState>(EMPTY_FORM);\n const [initialized, setInitialized] = useState(false);\n const [saveError, setSaveError] = useState('');\n\n // Step via URL search param\n const [searchParams, setSearchParams] = useSearchParams();\n const step = parseInt(searchParams.get('step') || '1', 10);\n const setStep = useCallback((s: number) => {\n setSearchParams((prev) => {\n const next = new URLSearchParams(prev);\n next.set('step', String(s));\n return next;\n }, { replace: false });\n }, [setSearchParams]);\n\n // Initialize form from existing record\n useEffect(() => {\n if (initialized) return;\n if (isNew) {\n setForm(EMPTY_FORM);\n setInitialized(true);\n return;\n }\n if (existing) {\n setForm(serverToForm(existing));\n setInitialized(true);\n }\n }, [existing, isNew, initialized]);\n\n const set = (field: keyof ServerFormState, value: any) =>\n setForm((f) => ({ ...f, [field]: value }));\n\n const isBuiltin = !!(existing?.transport_config as any)?.builtin;\n\n // Save\n const handleSave = () => {\n setSaveError('');\n const payload = formToPayload(form);\n\n if (existing) {\n updateServer.mutate(\n { id: existing.id, ...payload },\n { onSuccess: () => navigate('/mcp/servers') },\n );\n } else {\n createServer.mutate(payload, {\n onSuccess: () => navigate('/mcp/servers'),\n onError: (err) => setSaveError(err.message),\n });\n }\n };\n\n if (!isNew && isLoading) {\n return (\n <div className=\"animate-pulse space-y-4\">\n <div className=\"h-8 bg-surface-sunken rounded w-48\" />\n <div className=\"h-60 bg-surface-sunken rounded\" />\n </div>\n );\n }\n\n if (!isNew && !existing && !isLoading) {\n return <p className=\"text-sm text-text-secondary\">Server not found.</p>;\n }\n\n const isLast = step === STEP_LABELS.length;\n const isPending = createServer.isPending || updateServer.isPending;\n const error = saveError || (createServer.error as Error | null)?.message || (updateServer.error as Error | null)?.message;\n\n return (\n <div>\n <PageHeader title={isNew ? 'Register MCP Server' : existing?.name ?? ''} />\n\n <div className=\"max-w-3xl\">\n <StepIndicator steps={STEP_LABELS} currentStep={step - 1} onStepClick={(i) => setStep(i + 1)} />\n\n <div className=\"min-h-[360px] py-2\">\n {step === 1 && <TransportStep form={form} set={set} isBuiltin={isBuiltin} />}\n {step === 2 && <DiscoveryStep form={form} set={set} />}\n {step === 3 && <TestStep form={form} set={set} />}\n {step === 4 && <ReviewStep form={form} />}\n </div>\n\n {error && (\n <p className=\"text-xs text-status-error mt-4\">{error}</p>\n )}\n\n {/* Navigation */}\n <div className=\"flex justify-between items-center pt-4 border-t border-surface-border mt-4\">\n <div>\n {step > 1 && (\n <button onClick={() => setStep(step - 1)} className=\"btn-secondary text-xs\">\n Back\n </button>\n )}\n </div>\n <div className=\"flex gap-3\">\n <button onClick={() => navigate('/mcp/servers')} className=\"btn-ghost text-xs\">\n Cancel\n </button>\n {isLast ? (\n <button\n onClick={handleSave}\n disabled={!isStepValid(step, form) || isPending}\n className=\"btn-primary text-xs\"\n >\n {isPending ? 'Saving...' : existing ? 'Save' : 'Register'}\n </button>\n ) : (\n <button\n onClick={() => setStep(step + 1)}\n disabled={!isStepValid(step, form)}\n className=\"btn-primary text-xs\"\n >\n Next\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"names":["StepIndicator","steps","currentStep","onStepClick","jsx","label","i","done","active","clickable","jsxs","EMPTY_FORM","serverToForm","config","isBuiltin","mode","formToPayload","form","transport_config","a","STEP_LABELS","isStepValid","step","labelCls","hintCls","modes","TransportStep","set","m","disabled","e","Fragment","t","DiscoveryStep","cpInput","setCpInput","useState","addProvider","raw","v","removeProvider","p","x","handleCpKey","TagInput","tags","X","TestStep","test","useTestConnection","isInProcess","handleTest","payload","result","tools","ToolList","Loader2","CheckCircle2","XCircle","modeLabels","transportLabels","ReviewStep","Row","value","mono","McpServerDetailPage","serverId","useParams","isNew","navigate","useNavigate","existing","isLoading","useMcpServer","createServer","useCreateMcpServer","updateServer","useUpdateMcpServer","setForm","initialized","setInitialized","saveError","setSaveError","searchParams","setSearchParams","useSearchParams","setStep","useCallback","s","prev","next","useEffect","field","f","_a","handleSave","err","isLast","isPending","error","_b","_c","PageHeader"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-C3h0qGzG.js","sources":["../../src/components/common/layout/StepIndicator.tsx","../../src/pages/mcp/servers/detail/server-form-types.ts","../../src/pages/mcp/servers/detail/TransportStep.tsx","../../src/pages/mcp/servers/detail/DiscoveryStep.tsx","../../src/pages/mcp/servers/detail/TestStep.tsx","../../src/pages/mcp/servers/detail/ReviewStep.tsx","../../src/pages/mcp/servers/detail/McpServerDetailPage.tsx"],"sourcesContent":["interface StepIndicatorProps {\n steps: string[];\n currentStep: number;\n onStepClick?: (step: number) => void;\n}\n\nexport function StepIndicator({ steps, currentStep, onStepClick }: StepIndicatorProps) {\n return (\n <div className=\"flex items-center justify-center gap-1 pb-4 border-b border-surface-border mb-4\">\n {steps.map((label, i) => {\n const done = i < currentStep;\n const active = i === currentStep;\n const clickable = !!onStepClick;\n return (\n <div key={label} className=\"flex items-center gap-1\">\n {i > 0 && (\n <div className={`w-4 h-px ${done ? 'bg-accent' : 'bg-surface-border'}`} />\n )}\n <button\n type=\"button\"\n onClick={clickable ? () => onStepClick(i) : undefined}\n className={`flex items-center gap-1 ${clickable ? 'cursor-pointer' : 'cursor-default'}`}\n >\n <span\n className={`w-5 h-5 rounded-full text-[10px] font-semibold flex items-center justify-center shrink-0 transition-colors ${\n active\n ? 'bg-accent text-text-inverse'\n : done\n ? 'bg-accent-muted text-accent'\n : 'bg-surface-sunken text-text-tertiary'\n } ${clickable && !active ? 'hover:bg-accent-muted hover:text-accent' : ''}`}\n >\n {i + 1}\n </span>\n <span\n className={`text-[10px] font-semibold uppercase tracking-wider whitespace-nowrap transition-colors ${\n active ? 'text-text-primary' : 'text-text-tertiary'\n } ${clickable && !active ? 'hover:text-text-primary' : ''}`}\n >\n {label}\n </span>\n </button>\n </div>\n );\n })}\n </div>\n );\n}\n","import type { McpServerRecord, McpToolManifest } from '../../../../api/types';\n\nexport interface ServerFormState {\n name: string;\n description: string;\n mode: 'in-process' | 'network' | 'local-process';\n transport_type: 'stdio' | 'sse' | 'streamable-http';\n // stdio fields\n command: string;\n args: string;\n env_vars: string;\n // network fields\n url: string;\n // shared\n auto_connect: boolean;\n tags: string[];\n compile_hints: string;\n credential_providers: string[];\n discovered_tools: McpToolManifest[] | null;\n}\n\nexport const EMPTY_FORM: ServerFormState = {\n name: '',\n description: '',\n mode: 'network',\n transport_type: 'sse',\n command: '',\n args: '',\n env_vars: '{}',\n url: '',\n auto_connect: false,\n tags: [],\n compile_hints: '',\n credential_providers: [],\n discovered_tools: null,\n};\n\nexport function serverToForm(s: McpServerRecord): ServerFormState {\n const config = s.transport_config ?? {};\n const isBuiltin = !!(config as any).builtin;\n\n let mode: ServerFormState['mode'] = 'network';\n if (isBuiltin) mode = 'in-process';\n else if (s.transport_type === 'stdio') mode = 'local-process';\n\n return {\n name: s.name,\n description: s.description ?? '',\n mode,\n transport_type: s.transport_type,\n command: (config as any).command ?? '',\n args: ((config as any).args ?? []).join(', '),\n env_vars: (config as any).env ? JSON.stringify((config as any).env, null, 2) : '{}',\n url: (config as any).url ?? '',\n auto_connect: s.auto_connect,\n tags: s.tags ?? [],\n compile_hints: (s as any).compile_hints ?? '',\n credential_providers: s.credential_providers ?? [],\n discovered_tools: s.tool_manifest ?? null,\n };\n}\n\nexport function formToPayload(form: ServerFormState) {\n let transport_config: Record<string, unknown> = {};\n\n if (form.mode === 'local-process') {\n transport_config = {\n command: form.command.trim(),\n args: form.args.split(',').map((a) => a.trim()).filter(Boolean),\n env: form.env_vars.trim() ? JSON.parse(form.env_vars) : undefined,\n };\n } else if (form.mode === 'network') {\n transport_config = { url: form.url.trim() };\n }\n // in-process: transport_config stays empty (server manages it)\n\n return {\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n transport_type: form.mode === 'local-process' ? 'stdio' as const : form.transport_type,\n transport_config,\n auto_connect: form.auto_connect,\n tags: form.tags,\n compile_hints: form.compile_hints.trim() || undefined,\n credential_providers: form.credential_providers.length > 0 ? form.credential_providers : undefined,\n };\n}\n\nexport const STEP_LABELS = ['Transport', 'Discovery', 'Test', 'Review'];\n\nexport function isStepValid(step: number, form: ServerFormState): boolean {\n if (step === 1) {\n if (!form.name.trim()) return false;\n if (form.mode === 'network' && !form.url.trim()) return false;\n if (form.mode === 'local-process' && !form.command.trim()) return false;\n return true;\n }\n return true;\n}\n\nexport const labelCls = 'label';\nexport const hintCls = 'hint';\n","import type { ServerFormState } from './server-form-types';\nimport { labelCls, hintCls } from './server-form-types';\n\ninterface Props {\n form: ServerFormState;\n set: (field: keyof ServerFormState, value: any) => void;\n isBuiltin: boolean;\n}\n\nconst modes = [\n { value: 'in-process', label: 'In-Process', hint: 'Built-in server running inside the app' },\n { value: 'network', label: 'Network Service', hint: 'Remote server via SSE or Streamable HTTP' },\n { value: 'local-process', label: 'Local Process', hint: 'Spawn a local command via stdio' },\n] as const;\n\nexport function TransportStep({ form, set, isBuiltin }: Props) {\n return (\n <div className=\"space-y-5\">\n {/* Mode selector */}\n <div>\n <label className={labelCls}>Connection Mode</label>\n <div className=\"grid grid-cols-3 gap-3 mt-1\">\n {modes.map((m) => {\n const active = form.mode === m.value;\n const disabled = isBuiltin && m.value !== 'in-process';\n return (\n <button\n key={m.value}\n type=\"button\"\n disabled={disabled}\n onClick={() => {\n set('mode', m.value);\n if (m.value === 'local-process') set('transport_type', 'stdio');\n if (m.value === 'network') set('transport_type', 'sse');\n }}\n className={`text-left p-3 rounded-md border transition-colors ${\n active\n ? 'border-accent bg-accent/5'\n : disabled\n ? 'border-surface-border bg-surface-sunken opacity-50 cursor-not-allowed'\n : 'border-surface-border hover:border-text-tertiary cursor-pointer'\n }`}\n >\n <span className={`text-xs font-medium ${active ? 'text-accent' : 'text-text-primary'}`}>\n {m.label}\n </span>\n <span className=\"block text-[10px] text-text-tertiary mt-0.5\">{m.hint}</span>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Name + Description (always shown) */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className={labelCls}>Name</label>\n <input\n type=\"text\"\n value={form.name}\n onChange={(e) => set('name', e.target.value)}\n placeholder=\"e.g., vision-server\"\n className=\"input text-xs w-full\"\n disabled={isBuiltin}\n />\n </div>\n <div>\n <label className={labelCls}>Description</label>\n <input\n type=\"text\"\n value={form.description}\n onChange={(e) => set('description', e.target.value)}\n placeholder=\"Optional description\"\n className=\"input text-xs w-full\"\n />\n </div>\n </div>\n\n {/* In-Process: read-only info */}\n {form.mode === 'in-process' && (\n <div>\n <p className={hintCls}>\n This server runs in-process via InMemoryTransport. Transport is managed automatically — no configuration needed.\n </p>\n </div>\n )}\n\n {/* Network: URL + transport toggle */}\n {form.mode === 'network' && (\n <>\n <div>\n <label className={labelCls}>Server URL</label>\n <input\n type=\"text\"\n value={form.url}\n onChange={(e) => set('url', e.target.value)}\n placeholder=\"https://mcp-server.example.com/sse\"\n className=\"input text-xs w-full font-mono\"\n />\n </div>\n <div>\n <label className={labelCls}>Transport Protocol</label>\n <div className=\"flex gap-2 mt-1\">\n {(['sse', 'streamable-http'] as const).map((t) => (\n <button\n key={t}\n type=\"button\"\n onClick={() => set('transport_type', t)}\n className={`px-3 py-1.5 text-xs rounded-md border transition-colors ${\n form.transport_type === t\n ? 'border-accent bg-accent/5 text-accent font-medium'\n : 'border-surface-border text-text-secondary hover:border-text-tertiary'\n }`}\n >\n {t === 'sse' ? 'SSE' : 'Streamable HTTP'}\n </button>\n ))}\n </div>\n </div>\n </>\n )}\n\n {/* Local Process: command + args + env */}\n {form.mode === 'local-process' && (\n <>\n <div>\n <label className={labelCls}>Command</label>\n <input\n type=\"text\"\n value={form.command}\n onChange={(e) => set('command', e.target.value)}\n placeholder=\"e.g., npx\"\n className=\"input text-xs w-full font-mono\"\n />\n </div>\n <div>\n <label className={labelCls}>Arguments (comma-separated)</label>\n <input\n type=\"text\"\n value={form.args}\n onChange={(e) => set('args', e.target.value)}\n placeholder=\"e.g., -y, @modelcontextprotocol/server-filesystem, /tmp\"\n className=\"input text-xs w-full font-mono\"\n />\n </div>\n <div>\n <label className={labelCls}>Environment Variables (JSON)</label>\n <textarea\n value={form.env_vars}\n onChange={(e) => set('env_vars', e.target.value)}\n className=\"input-json w-full\"\n rows={3}\n spellCheck={false}\n />\n </div>\n </>\n )}\n\n {/* Auto-connect */}\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={form.auto_connect}\n onChange={(e) => set('auto_connect', e.target.checked)}\n className=\"w-4 h-4 rounded border-border accent-accent\"\n />\n <span className=\"text-xs text-text-primary\">Auto-connect on startup</span>\n </label>\n </div>\n );\n}\n","import { useState, type KeyboardEvent } from 'react';\nimport { X } from 'lucide-react';\nimport { TagInput } from '../../../../components/common/form/TagInput';\nimport type { ServerFormState } from './server-form-types';\nimport { labelCls, hintCls } from './server-form-types';\n\ninterface Props {\n form: ServerFormState;\n set: (field: keyof ServerFormState, value: any) => void;\n}\n\nexport function DiscoveryStep({ form, set }: Props) {\n const [cpInput, setCpInput] = useState('');\n\n const addProvider = (raw: string) => {\n const v = raw.trim().toLowerCase();\n if (v && !form.credential_providers.includes(v)) {\n set('credential_providers', [...form.credential_providers, v]);\n }\n setCpInput('');\n };\n\n const removeProvider = (p: string) => {\n set('credential_providers', form.credential_providers.filter((x) => x !== p));\n };\n\n const handleCpKey = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter' || e.key === ',') {\n e.preventDefault();\n addProvider(cpInput);\n } else if (e.key === 'Backspace' && !cpInput && form.credential_providers.length > 0) {\n removeProvider(form.credential_providers[form.credential_providers.length - 1]);\n }\n };\n\n return (\n <div className=\"space-y-5\">\n {/* Tags */}\n <div>\n <label className={labelCls}>Tags</label>\n <TagInput\n tags={form.tags}\n onChange={(tags) => set('tags', tags)}\n placeholder=\"Add tag (e.g., database, analytics)...\"\n />\n <p className={hintCls}>\n Tags enable tool discovery. Workflows filter available MCP servers by tags to find relevant tools.\n </p>\n </div>\n\n {/* Compile Hints */}\n <div>\n <label className={labelCls}>Compile Hints</label>\n <textarea\n value={form.compile_hints}\n onChange={(e) => set('compile_hints', e.target.value)}\n placeholder=\"Guidance for the workflow compiler when generating YAML from this server's tools...\"\n className=\"input text-xs w-full leading-relaxed\"\n rows={4}\n spellCheck={false}\n />\n <p className={hintCls}>\n Free-form text that guides the workflow compiler. Describe how tools should be composed, sequenced, or parameterized.\n </p>\n </div>\n\n {/* Credential Providers */}\n <div>\n <label className={labelCls}>Credential Providers</label>\n <div className=\"flex flex-wrap items-center gap-1.5 bg-surface-sunken border border-surface-border rounded-md px-2 py-1.5 focus-within:ring-1 focus-within:ring-accent-primary\">\n {form.credential_providers.map((p) => (\n <span\n key={p}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-accent/10 text-accent text-[11px] font-medium\"\n >\n {p}\n <button\n type=\"button\"\n onClick={() => removeProvider(p)}\n className=\"hover:text-status-error transition-colors\"\n >\n <X className=\"w-2.5 h-2.5\" />\n </button>\n </span>\n ))}\n <input\n type=\"text\"\n value={cpInput}\n onChange={(e) => setCpInput(e.target.value)}\n onKeyDown={handleCpKey}\n onBlur={() => { if (cpInput.trim()) addProvider(cpInput); }}\n placeholder={form.credential_providers.length === 0 ? 'Add provider (e.g., github, slack)...' : ''}\n className=\"flex-1 min-w-[80px] bg-transparent text-xs text-text-primary outline-none placeholder:text-text-tertiary\"\n />\n </div>\n <p className={hintCls}>\n IAM credential providers required by this server's tools. Users will be prompted to connect these before tool execution.\n </p>\n </div>\n </div>\n );\n}\n","import { CheckCircle2, XCircle, Loader2 } from 'lucide-react';\nimport { useTestConnection } from '../../../../api/mcp';\nimport type { ServerFormState } from './server-form-types';\nimport { formToPayload } from './server-form-types';\nimport { hintCls } from './server-form-types';\n\ninterface Props {\n form: ServerFormState;\n set: (field: keyof ServerFormState, value: any) => void;\n}\n\nexport function TestStep({ form, set }: Props) {\n const test = useTestConnection();\n const isInProcess = form.mode === 'in-process';\n\n const handleTest = () => {\n const payload = formToPayload(form);\n test.mutate(\n { transport_type: payload.transport_type, transport_config: payload.transport_config },\n {\n onSuccess: (result) => {\n if (result.success) {\n set('discovered_tools', result.tools);\n }\n },\n },\n );\n };\n\n const result = test.data;\n const tools = form.discovered_tools ?? result?.tools ?? [];\n\n return (\n <div className=\"space-y-5\">\n {isInProcess ? (\n <div>\n <p className=\"text-sm text-text-secondary\">\n In-process servers connect lazily on first tool call. No connection test needed.\n </p>\n {form.discovered_tools && form.discovered_tools.length > 0 && (\n <div className=\"mt-4\">\n <p className=\"text-xs text-text-tertiary mb-2\">\n {form.discovered_tools.length} tool{form.discovered_tools.length !== 1 ? 's' : ''} cached from last connection\n </p>\n <ToolList tools={form.discovered_tools} />\n </div>\n )}\n </div>\n ) : (\n <>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={handleTest}\n disabled={test.isPending}\n className=\"btn-primary text-xs\"\n >\n {test.isPending ? (\n <span className=\"flex items-center gap-1.5\">\n <Loader2 className=\"w-3 h-3 animate-spin\" />\n Connecting...\n </span>\n ) : (\n 'Test Connection'\n )}\n </button>\n {result?.success && (\n <span className=\"flex items-center gap-1 text-xs text-status-success\">\n <CheckCircle2 className=\"w-3.5 h-3.5\" />\n Connected — {tools.length} tool{tools.length !== 1 ? 's' : ''} discovered\n </span>\n )}\n {result && !result.success && (\n <span className=\"flex items-center gap-1 text-xs text-status-error\">\n <XCircle className=\"w-3.5 h-3.5\" />\n {result.error || 'Connection failed'}\n </span>\n )}\n </div>\n\n {tools.length > 0 && (\n <div>\n <p className=\"text-xs text-text-tertiary mb-2\">Discovered tools</p>\n <ToolList tools={tools} />\n </div>\n )}\n\n <p className={hintCls}>\n Tests connectivity by connecting to the server and listing available tools. The server must be reachable from this machine.\n </p>\n </>\n )}\n </div>\n );\n}\n\nfunction ToolList({ tools }: { tools: { name: string; description?: string }[] }) {\n return (\n <div className=\"max-h-[280px] overflow-y-auto border border-surface-border rounded-md divide-y divide-surface-border\">\n {tools.map((t) => (\n <div key={t.name} className=\"px-3 py-2\">\n <span className=\"text-xs font-medium text-text-primary font-mono\">{t.name}</span>\n {t.description && (\n <span className=\"block text-[10px] text-text-tertiary mt-0.5 line-clamp-2\">{t.description}</span>\n )}\n </div>\n ))}\n </div>\n );\n}\n","import type { ServerFormState } from './server-form-types';\nimport { labelCls } from './server-form-types';\n\ninterface Props {\n form: ServerFormState;\n}\n\nconst modeLabels: Record<string, string> = {\n 'in-process': 'In-Process',\n 'network': 'Network Service',\n 'local-process': 'Local Process',\n};\n\nconst transportLabels: Record<string, string> = {\n stdio: 'stdio',\n sse: 'SSE',\n 'streamable-http': 'Streamable HTTP',\n};\n\nexport function ReviewStep({ form }: Props) {\n const tools = form.discovered_tools ?? [];\n\n return (\n <div className=\"space-y-4\">\n <Row label=\"Name\" value={form.name} />\n {form.description && <Row label=\"Description\" value={form.description} />}\n <Row label=\"Mode\" value={modeLabels[form.mode] ?? form.mode} />\n\n {form.mode === 'network' && (\n <>\n <Row label=\"Transport\" value={transportLabels[form.transport_type] ?? form.transport_type} />\n <Row label=\"URL\" value={form.url} mono />\n </>\n )}\n {form.mode === 'local-process' && (\n <>\n <Row label=\"Command\" value={form.command} mono />\n {form.args && <Row label=\"Args\" value={form.args} mono />}\n </>\n )}\n\n <Row label=\"Auto-connect\" value={form.auto_connect ? 'Yes' : 'No'} />\n\n {form.tags.length > 0 && (\n <div>\n <label className={labelCls}>Tags</label>\n <div className=\"flex flex-wrap gap-1.5 mt-1\">\n {form.tags.map((t) => (\n <span key={t} className=\"px-2 py-0.5 rounded-full bg-accent/10 text-accent text-[11px] font-medium\">\n {t}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {form.credential_providers.length > 0 && (\n <div>\n <label className={labelCls}>Credential Providers</label>\n <div className=\"flex flex-wrap gap-1.5 mt-1\">\n {form.credential_providers.map((p) => (\n <span key={p} className=\"px-2 py-0.5 rounded-full bg-accent/10 text-accent text-[11px] font-medium\">\n {p}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {form.compile_hints && <Row label=\"Compile Hints\" value={form.compile_hints} />}\n\n {tools.length > 0 && (\n <Row label=\"Discovered Tools\" value={`${tools.length} tool${tools.length !== 1 ? 's' : ''}`} />\n )}\n </div>\n );\n}\n\nfunction Row({ label, value, mono }: { label: string; value: string; mono?: boolean }) {\n return (\n <div>\n <label className={labelCls}>{label}</label>\n <p className={`text-xs text-text-primary mt-0.5 ${mono ? 'font-mono' : ''}`}>{value}</p>\n </div>\n );\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport { useParams, useNavigate, useSearchParams } from 'react-router-dom';\nimport { useMcpServer, useCreateMcpServer, useUpdateMcpServer } from '../../../../api/mcp';\nimport { StepIndicator } from '../../../../components/common/layout/StepIndicator';\nimport { PageHeader } from '../../../../components/common/layout/PageHeader';\nimport {\n EMPTY_FORM,\n serverToForm,\n formToPayload,\n STEP_LABELS,\n isStepValid,\n} from './server-form-types';\nimport type { ServerFormState } from './server-form-types';\nimport { TransportStep } from './TransportStep';\nimport { DiscoveryStep } from './DiscoveryStep';\nimport { TestStep } from './TestStep';\nimport { ReviewStep } from './ReviewStep';\n\nexport function McpServerDetailPage() {\n const { serverId } = useParams<{ serverId: string }>();\n const isNew = !serverId;\n const navigate = useNavigate();\n const { data: existing, isLoading } = useMcpServer(serverId ?? '');\n const createServer = useCreateMcpServer();\n const updateServer = useUpdateMcpServer();\n\n const [form, setForm] = useState<ServerFormState>(EMPTY_FORM);\n const [initialized, setInitialized] = useState(false);\n const [saveError, setSaveError] = useState('');\n\n // Step via URL search param\n const [searchParams, setSearchParams] = useSearchParams();\n const step = parseInt(searchParams.get('step') || '1', 10);\n const setStep = useCallback((s: number) => {\n setSearchParams((prev) => {\n const next = new URLSearchParams(prev);\n next.set('step', String(s));\n return next;\n }, { replace: false });\n }, [setSearchParams]);\n\n // Initialize form from existing record\n useEffect(() => {\n if (initialized) return;\n if (isNew) {\n setForm(EMPTY_FORM);\n setInitialized(true);\n return;\n }\n if (existing) {\n setForm(serverToForm(existing));\n setInitialized(true);\n }\n }, [existing, isNew, initialized]);\n\n const set = (field: keyof ServerFormState, value: any) =>\n setForm((f) => ({ ...f, [field]: value }));\n\n const isBuiltin = !!(existing?.transport_config as any)?.builtin;\n\n // Save\n const handleSave = () => {\n setSaveError('');\n const payload = formToPayload(form);\n\n if (existing) {\n updateServer.mutate(\n { id: existing.id, ...payload },\n { onSuccess: () => navigate('/mcp/servers') },\n );\n } else {\n createServer.mutate(payload, {\n onSuccess: () => navigate('/mcp/servers'),\n onError: (err) => setSaveError(err.message),\n });\n }\n };\n\n if (!isNew && isLoading) {\n return (\n <div className=\"animate-pulse space-y-4\">\n <div className=\"h-8 bg-surface-sunken rounded w-48\" />\n <div className=\"h-60 bg-surface-sunken rounded\" />\n </div>\n );\n }\n\n if (!isNew && !existing && !isLoading) {\n return <p className=\"text-sm text-text-secondary\">Server not found.</p>;\n }\n\n const isLast = step === STEP_LABELS.length;\n const isPending = createServer.isPending || updateServer.isPending;\n const error = saveError || (createServer.error as Error | null)?.message || (updateServer.error as Error | null)?.message;\n\n return (\n <div>\n <PageHeader title={isNew ? 'Register MCP Server' : existing?.name ?? ''} />\n\n <div className=\"max-w-3xl\">\n <StepIndicator steps={STEP_LABELS} currentStep={step - 1} onStepClick={(i) => setStep(i + 1)} />\n\n <div className=\"min-h-[360px] py-2\">\n {step === 1 && <TransportStep form={form} set={set} isBuiltin={isBuiltin} />}\n {step === 2 && <DiscoveryStep form={form} set={set} />}\n {step === 3 && <TestStep form={form} set={set} />}\n {step === 4 && <ReviewStep form={form} />}\n </div>\n\n {error && (\n <p className=\"text-xs text-status-error mt-4\">{error}</p>\n )}\n\n {/* Navigation */}\n <div className=\"flex justify-between items-center pt-4 border-t border-surface-border mt-4\">\n <div>\n {step > 1 && (\n <button onClick={() => setStep(step - 1)} className=\"btn-secondary text-xs\">\n Back\n </button>\n )}\n </div>\n <div className=\"flex gap-3\">\n <button onClick={() => navigate('/mcp/servers')} className=\"btn-ghost text-xs\">\n Cancel\n </button>\n {isLast ? (\n <button\n onClick={handleSave}\n disabled={!isStepValid(step, form) || isPending}\n className=\"btn-primary text-xs\"\n >\n {isPending ? 'Saving...' : existing ? 'Save' : 'Register'}\n </button>\n ) : (\n <button\n onClick={() => setStep(step + 1)}\n disabled={!isStepValid(step, form)}\n className=\"btn-primary text-xs\"\n >\n Next\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"names":["StepIndicator","steps","currentStep","onStepClick","jsx","label","i","done","active","clickable","jsxs","EMPTY_FORM","serverToForm","config","isBuiltin","mode","formToPayload","form","transport_config","a","STEP_LABELS","isStepValid","step","labelCls","hintCls","modes","TransportStep","set","m","disabled","e","Fragment","t","DiscoveryStep","cpInput","setCpInput","useState","addProvider","raw","v","removeProvider","p","x","handleCpKey","TagInput","tags","X","TestStep","test","useTestConnection","isInProcess","handleTest","payload","result","tools","ToolList","Loader2","CheckCircle2","XCircle","modeLabels","transportLabels","ReviewStep","Row","value","mono","McpServerDetailPage","serverId","useParams","isNew","navigate","useNavigate","existing","isLoading","useMcpServer","createServer","useCreateMcpServer","updateServer","useUpdateMcpServer","setForm","initialized","setInitialized","saveError","setSaveError","searchParams","setSearchParams","useSearchParams","setStep","useCallback","s","prev","next","useEffect","field","f","_a","handleSave","err","isLast","isPending","error","_b","_c","PageHeader"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as p,j as e}from"./vendor-query-B2UbickB.js";import{u as L,a as M,b as D,c as I}from"./mcp-
|
|
2
|
-
//# sourceMappingURL=index-
|
|
1
|
+
import{a as p,j as e}from"./vendor-query-B2UbickB.js";import{u as L,a as M,b as D,c as I}from"./mcp-1lzlgtS8.js";import{E as R}from"./EmptyState-BcsfPq9T.js";import{C as z}from"./ConfirmDeleteModal-D9_1b4MW.js";import{P as k}from"./PageHeader-DJo7yMUR.js";import{F,a as _,b as P}from"./FilterBar-B4Mk2PvT.js";import{S as $}from"./StickyPagination-CqT9Q1I6.js";import{u as q}from"./useFilterParams-x-Dg0Vgz.js";import{S as A,T as B}from"./ToolTestPanel-CsPsyvQq.js";import{R as O,a as b}from"./RowActions-BA9L9djf.js";import{S as H}from"./StatusBadge-DZ9137bI.js";import{T as J}from"./ToolPill-BW0iRwZu.js";import{o as G,am as Q,an as U,Q as W,p as V,P as X}from"./vendor-icons-DOIDKgo6.js";import{c as Y}from"./vendor-react-CXumBFUA.js";import"./index-DwWP-Z_c.js";import"./Modal-CSrxpXeM.js";import"./RunAsSelector-mhusrlYE.js";import"./BotPicker-B1RdaNuY.js";import"./bots-CWMN-KUI.js";import"./helpers-DzO-OGPe.js";function Z(s){const[t,a]=p.useState(()=>{try{const o=localStorage.getItem(s);if(o){const u=JSON.parse(o);if(Array.isArray(u))return new Set(u)}}catch{}return new Set}),i=p.useCallback(o=>{try{localStorage.setItem(s,JSON.stringify([...o]))}catch{}},[s]),n=p.useCallback(o=>{a(u=>{const x=new Set(u);return x.has(o)?x.delete(o):x.add(o),i(x),x})},[i]),m=p.useCallback(o=>t.has(o),[t]);return{expandedIds:t,toggle:n,isExpanded:m}}function K(s){var t,a;return!!((t=s.metadata)!=null&&t.builtin)||!!((a=s.transport_config)!=null&&a.builtin)}function ee(s,t){var n;if(!t)return!0;const a=t.toLowerCase();return s.name.toLowerCase().includes(a)||(n=s.description)!=null&&n.toLowerCase().includes(a)||(s.tags??[]).some(m=>m.toLowerCase().includes(a))?!0:(s.tool_manifest??[]).some(m=>{var o;return m.name.toLowerCase().includes(a)||((o=m.description)==null?void 0:o.toLowerCase().includes(a))})}function te(s,t){if(!t)return s;const a=t.toLowerCase();return s.filter(i=>{var n;return i.name.toLowerCase().includes(a)||((n=i.description)==null?void 0:n.toLowerCase().includes(a))})}function se({server:s,expanded:t,onToggle:a,onEdit:i,onDelete:n,onTryTool:m,connect:o,disconnect:u,visibleTools:x}){const l=s.tool_manifest??[],f=K(s),g=s.tags??[];return e.jsxs(e.Fragment,{children:[e.jsxs("tr",{onClick:l.length>0?a:void 0,className:`group/row border-b border-surface-border/50 transition-colors duration-100 ${l.length>0?"cursor-pointer row-hover":""}`,children:[e.jsx("td",{className:"px-6 py-2.5",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:`transition-transform duration-150 ${t?"rotate-90":""} ${l.length===0?"opacity-0":"text-text-tertiary"}`,children:e.jsx(G,{size:14})}),e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx(A,{name:s.name,serverId:s.id,short:!1}),l.length>0&&e.jsx("sup",{className:"text-[9px] font-normal text-accent/70",children:l.length})]}),g.length>0&&e.jsxs("div",{className:"flex gap-1 ml-auto shrink-0",children:[g.slice(0,3).map(c=>e.jsx("span",{className:"inline-block px-1.5 py-0 text-[9px] text-text-tertiary bg-surface-sunken rounded",children:c},c)),g.length>3&&e.jsx("span",{className:"text-[9px] text-text-quaternary",title:g.slice(3).join(", "),children:"…"})]})]})}),e.jsx("td",{className:"px-4 py-2.5 w-28 whitespace-nowrap",children:e.jsx(H,{status:s.status})}),e.jsx("td",{className:"px-4 py-2.5 w-16",children:e.jsxs(O,{children:[!f&&(s.status==="connected"?e.jsx(b,{icon:Q,title:"Disconnect server",onClick:()=>u.mutate(s.id)}):e.jsx(b,{icon:U,title:"Connect server",onClick:()=>o.mutate(s.id),colorClass:"text-text-tertiary hover:text-status-success"})),e.jsx(b,{icon:W,title:"Edit server",onClick:i}),!f&&e.jsx(b,{icon:V,title:"Delete server",onClick:n,colorClass:"text-text-tertiary hover:text-status-error"})]})})]}),t&&x.map(c=>e.jsxs("tr",{onClick:()=>m(c),className:"group/row cursor-pointer hover:bg-surface-hover/50 transition-colors border-b border-surface-border/15",children:[e.jsxs("td",{className:"pl-14 pr-6 py-2.5",children:[e.jsx(J,{name:c.name,size:"md"}),c.description&&e.jsx("p",{className:"text-[11px] leading-snug text-text-quaternary mt-0.5",children:c.description})]}),e.jsx("td",{className:"px-4 py-2.5 w-28"}),e.jsx("td",{className:"px-4 py-2.5 w-16",children:e.jsx("div",{className:"flex items-center justify-end",children:e.jsx("button",{onClick:h=>{h.stopPropagation(),m(c)},className:"opacity-0 group-hover/row:opacity-100 transition-opacity text-text-tertiary hover:text-accent",title:"Try tool",children:e.jsx(X,{className:"w-3.5 h-3.5",strokeWidth:1.5})})})})]},c.name))]})}function Se(){const s=Y(),{filters:t,setFilter:a,pagination:i}=q({filters:{status:"",search:"",tag:""}}),{data:n,isLoading:m}=L({status:t.status||void 0,search:t.search||void 0,tags:t.tag||void 0}),o=M(),u=D(),x=I(),[l,f]=p.useState(null),{expandedIds:g,toggle:c}=Z("lt:expanded:mcp-servers"),[h,w]=p.useState(null),j=(n==null?void 0:n.servers)??[],y=(n==null?void 0:n.total)??0,T=p.useMemo(()=>{const r=new Set;for(const d of j)for(const C of d.tags??[])r.add(C);return[...r].sort().map(d=>({value:d,label:d}))},[j]),v=p.useMemo(()=>t.search?j.filter(r=>ee(r,t.search)):j,[j,t.search]);p.useEffect(()=>{if(!t.search)return;const r=t.search.toLowerCase();for(const d of v)(d.tool_manifest??[]).some(S=>{var N;return S.name.toLowerCase().includes(r)||((N=S.description)==null?void 0:N.toLowerCase().includes(r))})&&!g.has(d.id)&&c(d.id)},[t.search,v]);const E=()=>{l&&x.mutate(l.id,{onSuccess:()=>f(null)})};return m?e.jsxs("div",{children:[e.jsx(k,{title:"Servers & Tools"}),e.jsx("div",{className:"animate-pulse space-y-0",children:Array.from({length:5}).map((r,d)=>e.jsx("div",{className:"h-14 border-b last:border-b-0 px-6 flex items-center",children:e.jsx("div",{className:"h-3 bg-surface-sunken rounded w-full"})},d))})]}):e.jsxs("div",{children:[e.jsx(k,{title:"Servers & Tools",docsHash:"#docs:dashboard.md:mcp-server-tools",actions:e.jsx("button",{onClick:()=>s("/mcp/servers/new"),className:"btn-primary text-xs",children:"Register Server"})}),e.jsx("p",{className:"text-sm text-text-secondary mb-6 max-w-2xl leading-relaxed",children:"Registered MCP servers and their available tools. Each server exposes tools that can be used by the MCP Tool Designer."}),e.jsxs(F,{children:[e.jsx(_,{label:"Search",value:t.search,onChange:r=>a("search",r),placeholder:"Server or tool name..."}),e.jsx(P,{label:"Tag",value:t.tag,onChange:r=>a("tag",r),options:T}),e.jsx(P,{label:"Status",value:t.status,onChange:r=>a("status",r),options:[{value:"registered",label:"Registered"},{value:"connected",label:"Connected"},{value:"error",label:"Error"},{value:"disconnected",label:"Disconnected"}]})]}),e.jsxs("div",{className:"flex gap-0 ",children:[e.jsxs("div",{className:`${h?"flex-1 min-w-0":"w-full"} transition-all`,children:[v.length===0?e.jsx(R,{title:"No servers found"}):e.jsxs("table",{className:"w-full",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b",children:[e.jsx("th",{className:"sticky top-[2.75rem] z-10 bg-surface px-6 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary",children:"Server / Tool"}),e.jsx("th",{className:"sticky top-[2.75rem] z-10 bg-surface px-4 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary w-28",children:"Status"}),e.jsx("th",{className:"sticky top-[2.75rem] z-10 bg-surface w-16"})]})}),e.jsx("tbody",{children:v.map(r=>e.jsx(se,{server:r,expanded:g.has(r.id),onToggle:()=>c(r.id),onEdit:()=>s(`/mcp/servers/${r.id}`),onDelete:()=>f(r),onTryTool:d=>w({serverId:r.id,serverName:r.name,tool:d}),connect:o,disconnect:u,visibleTools:te(r.tool_manifest??[],t.search)},r.id))})]}),e.jsx($,{page:i.page,totalPages:i.totalPages(y),onPageChange:i.setPage,total:y,pageSize:i.pageSize,onPageSizeChange:i.setPageSize})]}),h&&e.jsx("div",{className:"w-[380px] shrink-0 sticky top-0 max-h-screen overflow-y-auto",children:e.jsx(B,{serverId:h.serverId,serverName:h.serverName,tool:h.tool,onClose:()=>w(null)})})]}),e.jsx(z,{open:!!l,onClose:()=>f(null),onConfirm:E,title:"Delete MCP Server",description:e.jsxs(e.Fragment,{children:["Delete"," ",e.jsx("span",{className:"font-medium text-text-primary",children:l==null?void 0:l.name}),"? This will remove the server registration."]}),isPending:x.isPending,error:x.error})]})}export{Se as McpServersPage};
|
|
2
|
+
//# sourceMappingURL=index-C5Yc3TT7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-CxlsLEr1.js","sources":["../../src/hooks/useExpandedRows.ts","../../src/pages/mcp/servers/helpers.ts","../../src/pages/mcp/servers/ServerRow.tsx","../../src/pages/mcp/servers/McpServersPage.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\n\n/**\n * Track expanded row IDs with localStorage persistence.\n *\n * Resilient: if a stored ID no longer exists in the data, it's silently ignored.\n * Never blocks rendering — reads from localStorage synchronously on mount,\n * writes asynchronously on change.\n */\nexport function useExpandedRows(storageKey: string): {\n expandedIds: Set<string>;\n toggle: (id: string) => void;\n isExpanded: (id: string) => boolean;\n} {\n const [expandedIds, setExpandedIds] = useState<Set<string>>(() => {\n try {\n const raw = localStorage.getItem(storageKey);\n if (raw) {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed)) return new Set(parsed);\n }\n } catch { /* corrupted or unavailable — start empty */ }\n return new Set();\n });\n\n const persist = useCallback((next: Set<string>) => {\n try {\n localStorage.setItem(storageKey, JSON.stringify([...next]));\n } catch { /* quota exceeded or unavailable — ignore */ }\n }, [storageKey]);\n\n const toggle = useCallback((id: string) => {\n setExpandedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n persist(next);\n return next;\n });\n }, [persist]);\n\n const isExpanded = useCallback((id: string) => expandedIds.has(id), [expandedIds]);\n\n return { expandedIds, toggle, isExpanded };\n}\n","import type { McpServerRecord, McpToolManifest } from '../../../api/types';\n\nexport function isBuiltIn(row: McpServerRecord): boolean {\n return !!(row.metadata as Record<string, unknown> | null)?.builtin\n || !!(row.transport_config as Record<string, unknown> | null)?.builtin;\n}\n\n/** Check if a server or any of its tools match the search term */\nexport function matchesSearch(server: McpServerRecord, search: string): boolean {\n if (!search) return true;\n const q = search.toLowerCase();\n if (server.name.toLowerCase().includes(q)) return true;\n if (server.description?.toLowerCase().includes(q)) return true;\n if ((server.tags ?? []).some((t) => t.toLowerCase().includes(q))) return true;\n const tools = (server.tool_manifest ?? []) as McpToolManifest[];\n return tools.some(\n (t) => t.name.toLowerCase().includes(q) || t.description?.toLowerCase().includes(q),\n );\n}\n\n/** Filter tools within a server that match the search term */\nexport function filterTools(tools: McpToolManifest[], search: string): McpToolManifest[] {\n if (!search) return tools;\n const q = search.toLowerCase();\n return tools.filter(\n (t) => t.name.toLowerCase().includes(q) || t.description?.toLowerCase().includes(q),\n );\n}\n","import { ChevronRight, Pencil, Trash2, Plug, Unplug, Play } from 'lucide-react';\nimport { RowAction, RowActionGroup } from '../../../components/common/layout/RowActions';\nimport {\n useConnectMcpServer,\n useDisconnectMcpServer,\n} from '../../../api/mcp';\nimport { StatusBadge } from '../../../components/common/display/StatusBadge';\nimport { ToolPill } from '../../../components/common/display/ToolPill';\nimport { ServerName } from '../../../components/common/display/ServerName';\n\nimport type { McpServerRecord, McpToolManifest } from '../../../api/types';\nimport { isBuiltIn } from './helpers';\n\nexport function ServerRow({\n server,\n expanded,\n onToggle,\n onEdit,\n onDelete,\n onTryTool,\n connect,\n disconnect,\n visibleTools,\n}: {\n server: McpServerRecord;\n expanded: boolean;\n onToggle: () => void;\n onEdit: () => void;\n onDelete: () => void;\n onTryTool: (tool: McpToolManifest) => void;\n connect: ReturnType<typeof useConnectMcpServer>;\n disconnect: ReturnType<typeof useDisconnectMcpServer>;\n visibleTools: McpToolManifest[];\n}) {\n const allTools = (server.tool_manifest ?? []) as McpToolManifest[];\n const builtin = isBuiltIn(server);\n const tags = server.tags ?? [];\n\n return (\n <>\n {/* Server header row */}\n <tr\n onClick={allTools.length > 0 ? onToggle : undefined}\n className={`group/row border-b border-surface-border/50 transition-colors duration-100 ${\n allTools.length > 0 ? 'cursor-pointer row-hover' : ''\n }`}\n >\n {/* Name + tags */}\n <td className=\"px-6 py-2.5\">\n <div className=\"flex items-center gap-3\">\n <span className={`transition-transform duration-150 ${expanded ? 'rotate-90' : ''} ${allTools.length === 0 ? 'opacity-0' : 'text-text-tertiary'}`}>\n <ChevronRight size={14} />\n </span>\n <span className=\"flex items-center gap-1.5\">\n <ServerName name={server.name} serverId={server.id} short={false} />\n {allTools.length > 0 && (\n <sup className=\"text-[9px] font-normal text-accent/70\">{allTools.length}</sup>\n )}\n </span>\n {tags.length > 0 && (\n <div className=\"flex gap-1 ml-auto shrink-0\">\n {tags.slice(0, 3).map((tag) => (\n <span key={tag} className=\"inline-block px-1.5 py-0 text-[9px] text-text-tertiary bg-surface-sunken rounded\">\n {tag}\n </span>\n ))}\n {tags.length > 3 && (\n <span className=\"text-[9px] text-text-quaternary\" title={tags.slice(3).join(', ')}>…</span>\n )}\n </div>\n )}\n </div>\n </td>\n\n {/* Status */}\n <td className=\"px-4 py-2.5 w-28 whitespace-nowrap\">\n <StatusBadge status={server.status} />\n </td>\n\n {/* Actions */}\n <td className=\"px-4 py-2.5 w-16\">\n <RowActionGroup>\n {!builtin && (\n server.status === 'connected' ? (\n <RowAction\n icon={Unplug}\n title=\"Disconnect server\"\n onClick={() => disconnect.mutate(server.id)}\n />\n ) : (\n <RowAction\n icon={Plug}\n title=\"Connect server\"\n onClick={() => connect.mutate(server.id)}\n colorClass=\"text-text-tertiary hover:text-status-success\"\n />\n )\n )}\n <RowAction\n icon={Pencil}\n title=\"Edit server\"\n onClick={onEdit}\n />\n {!builtin && (\n <RowAction\n icon={Trash2}\n title=\"Delete server\"\n onClick={onDelete}\n colorClass=\"text-text-tertiary hover:text-status-error\"\n />\n )}\n </RowActionGroup>\n </td>\n </tr>\n\n {/* Expanded tool rows — real table rows for column alignment */}\n {expanded && visibleTools.map((tool) => (\n <tr\n key={tool.name}\n onClick={() => onTryTool(tool)}\n className=\"group/row cursor-pointer hover:bg-surface-hover/50 transition-colors border-b border-surface-border/15\"\n >\n {/* Tool name + description */}\n <td className=\"pl-14 pr-6 py-2.5\">\n <ToolPill name={tool.name} size=\"md\" />\n {tool.description && (\n <p className=\"text-[11px] leading-snug text-text-quaternary mt-0.5\">{tool.description}</p>\n )}\n </td>\n\n {/* Status — empty for tools */}\n <td className=\"px-4 py-2.5 w-28\" />\n\n {/* Actions — play on hover */}\n <td className=\"px-4 py-2.5 w-16\">\n <div className=\"flex items-center justify-end\">\n <button\n onClick={(e) => { e.stopPropagation(); onTryTool(tool); }}\n className=\"opacity-0 group-hover/row:opacity-100 transition-opacity text-text-tertiary hover:text-accent\"\n title=\"Try tool\"\n >\n <Play className=\"w-3.5 h-3.5\" strokeWidth={1.5} />\n </button>\n </div>\n </td>\n </tr>\n ))}\n </>\n );\n}\n","import { useState, useMemo, useEffect } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n useMcpServers,\n useConnectMcpServer,\n useDisconnectMcpServer,\n useDeleteMcpServer,\n} from '../../../api/mcp';\nimport { EmptyState } from '../../../components/common/display/EmptyState';\nimport { ConfirmDeleteModal } from '../../../components/common/modal/ConfirmDeleteModal';\nimport type { McpServerRecord, McpToolManifest } from '../../../api/types';\nimport { PageHeader } from '../../../components/common/layout/PageHeader';\nimport { FilterBar, FilterSelect, FilterInput } from '../../../components/common/data/FilterBar';\nimport { StickyPagination } from '../../../components/common/data/StickyPagination';\nimport { useFilterParams } from '../../../hooks/useFilterParams';\nimport { useExpandedRows } from '../../../hooks/useExpandedRows';\nimport { ToolTestPanel } from '../../../components/common/test/ToolTestPanel';\nimport { matchesSearch, filterTools } from './helpers';\nimport { ServerRow } from './ServerRow';\n\nexport function McpServersPage() {\n const navigate = useNavigate();\n const { filters, setFilter, pagination } = useFilterParams({\n filters: { status: '', search: '', tag: '' },\n });\n\n const { data, isLoading } = useMcpServers({\n status: filters.status || undefined,\n search: filters.search || undefined,\n tags: filters.tag || undefined,\n });\n const connect = useConnectMcpServer();\n const disconnect = useDisconnectMcpServer();\n const deleteServer = useDeleteMcpServer();\n\n const [confirmDelete, setConfirmDelete] = useState<McpServerRecord | null>(null);\n const { expandedIds, toggle: toggleExpand } = useExpandedRows('lt:expanded:mcp-servers');\n const [tryTool, setTryTool] = useState<{\n serverId: string;\n serverName: string;\n tool: McpToolManifest;\n } | null>(null);\n\n const servers = data?.servers ?? [];\n const total = data?.total ?? 0;\n\n // Derive unique tags from current result set for the filter dropdown\n const tagOptions = useMemo(() => {\n const allTags = new Set<string>();\n for (const s of servers) {\n for (const t of s.tags ?? []) allTags.add(t);\n }\n return [...allTags].sort().map((t) => ({ value: t, label: t }));\n }, [servers]);\n\n // Client-side search filtering for tool-level matches within expanded rows\n const filteredServers = useMemo(() => {\n if (!filters.search) return servers;\n return servers.filter((s) => matchesSearch(s, filters.search));\n }, [servers, filters.search]);\n\n // Auto-expand servers whose tools match the search (so results are visible)\n useEffect(() => {\n if (!filters.search) return;\n const q = filters.search.toLowerCase();\n for (const s of filteredServers) {\n const tools = (s.tool_manifest ?? []) as McpToolManifest[];\n const hasToolMatch = tools.some(\n (t) => t.name.toLowerCase().includes(q) || t.description?.toLowerCase().includes(q),\n );\n if (hasToolMatch && !expandedIds.has(s.id)) {\n toggleExpand(s.id);\n }\n }\n }, [filters.search, filteredServers]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const handleDelete = () => {\n if (!confirmDelete) return;\n deleteServer.mutate(confirmDelete.id, {\n onSuccess: () => setConfirmDelete(null),\n });\n };\n\n if (isLoading) {\n return (\n <div>\n <PageHeader title=\"Servers & Tools\" />\n <div className=\"animate-pulse space-y-0\">\n {Array.from({ length: 5 }).map((_, i) => (\n <div key={i} className=\"h-14 border-b last:border-b-0 px-6 flex items-center\">\n <div className=\"h-3 bg-surface-sunken rounded w-full\" />\n </div>\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div>\n <PageHeader\n title=\"Servers & Tools\"\n docsHash=\"#docs:dashboard.md:mcp-server-tools\"\n actions={\n <button\n onClick={() => navigate('/mcp/servers/new')}\n className=\"btn-primary text-xs\"\n >\n Register Server\n </button>\n }\n />\n\n <p className=\"text-sm text-text-secondary mb-6 max-w-2xl leading-relaxed\">\n Registered MCP servers and their available tools. Each server exposes tools that can be used by the MCP Tool Designer.\n </p>\n\n <FilterBar>\n <FilterInput\n label=\"Search\"\n value={filters.search}\n onChange={(v) => setFilter('search', v)}\n placeholder=\"Server or tool name...\"\n />\n <FilterSelect\n label=\"Tag\"\n value={filters.tag}\n onChange={(v) => setFilter('tag', v)}\n options={tagOptions}\n />\n <FilterSelect\n label=\"Status\"\n value={filters.status}\n onChange={(v) => setFilter('status', v)}\n options={[\n { value: 'registered', label: 'Registered' },\n { value: 'connected', label: 'Connected' },\n { value: 'error', label: 'Error' },\n { value: 'disconnected', label: 'Disconnected' },\n ]}\n />\n </FilterBar>\n\n <div className={`flex gap-0 ${tryTool ? '' : ''}`}>\n {/* Server list */}\n <div className={`${tryTool ? 'flex-1 min-w-0' : 'w-full'} transition-all`}>\n {filteredServers.length === 0 ? (\n <EmptyState title=\"No servers found\" />\n ) : (\n <table className=\"w-full\">\n <thead>\n <tr className=\"border-b\">\n <th className=\"sticky top-[2.75rem] z-10 bg-surface px-6 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary\">\n Server / Tool\n </th>\n <th className=\"sticky top-[2.75rem] z-10 bg-surface px-4 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary w-28\">\n Status\n </th>\n <th className=\"sticky top-[2.75rem] z-10 bg-surface w-16\" />\n </tr>\n </thead>\n <tbody>\n {filteredServers.map((server) => (\n <ServerRow\n key={server.id}\n server={server}\n expanded={expandedIds.has(server.id)}\n onToggle={() => toggleExpand(server.id)}\n onEdit={() => navigate(`/mcp/servers/${server.id}`)}\n onDelete={() => setConfirmDelete(server)}\n onTryTool={(tool) =>\n setTryTool({\n serverId: server.id,\n serverName: server.name,\n tool,\n })\n }\n connect={connect}\n disconnect={disconnect}\n visibleTools={filterTools(\n (server.tool_manifest ?? []) as McpToolManifest[],\n filters.search,\n )}\n />\n ))}\n </tbody>\n </table>\n )}\n\n <StickyPagination\n page={pagination.page}\n totalPages={pagination.totalPages(total)}\n onPageChange={pagination.setPage}\n total={total}\n pageSize={pagination.pageSize}\n onPageSizeChange={pagination.setPageSize}\n />\n </div>\n\n {/* Test panel — slides in from right */}\n {tryTool && (\n <div className=\"w-[380px] shrink-0 sticky top-0 max-h-screen overflow-y-auto\">\n <ToolTestPanel\n serverId={tryTool.serverId}\n serverName={tryTool.serverName}\n tool={tryTool.tool}\n onClose={() => setTryTool(null)}\n />\n </div>\n )}\n </div>\n\n {/* Delete confirmation modal */}\n <ConfirmDeleteModal\n open={!!confirmDelete}\n onClose={() => setConfirmDelete(null)}\n onConfirm={handleDelete}\n title=\"Delete MCP Server\"\n description={\n <>\n Delete{' '}\n <span className=\"font-medium text-text-primary\">{confirmDelete?.name}</span>?\n This will remove the server registration.\n </>\n }\n isPending={deleteServer.isPending}\n error={deleteServer.error as Error | null}\n />\n </div>\n );\n}\n"],"names":["useExpandedRows","storageKey","expandedIds","setExpandedIds","useState","raw","parsed","persist","useCallback","next","toggle","id","prev","isExpanded","isBuiltIn","row","_a","_b","matchesSearch","server","search","q","t","filterTools","tools","ServerRow","expanded","onToggle","onEdit","onDelete","onTryTool","connect","disconnect","visibleTools","allTools","builtin","tags","jsxs","Fragment","jsx","ChevronRight","ServerName","tag","StatusBadge","RowActionGroup","RowAction","Unplug","Plug","Pencil","Trash2","tool","ToolPill","e","Play","McpServersPage","navigate","useNavigate","filters","setFilter","pagination","useFilterParams","data","isLoading","useMcpServers","useConnectMcpServer","useDisconnectMcpServer","deleteServer","useDeleteMcpServer","confirmDelete","setConfirmDelete","toggleExpand","tryTool","setTryTool","servers","total","tagOptions","useMemo","allTags","s","filteredServers","useEffect","handleDelete","PageHeader","_","i","FilterBar","FilterInput","v","FilterSelect","EmptyState","StickyPagination","ToolTestPanel","ConfirmDeleteModal"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-C5Yc3TT7.js","sources":["../../src/hooks/useExpandedRows.ts","../../src/pages/mcp/servers/helpers.ts","../../src/pages/mcp/servers/ServerRow.tsx","../../src/pages/mcp/servers/McpServersPage.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\n\n/**\n * Track expanded row IDs with localStorage persistence.\n *\n * Resilient: if a stored ID no longer exists in the data, it's silently ignored.\n * Never blocks rendering — reads from localStorage synchronously on mount,\n * writes asynchronously on change.\n */\nexport function useExpandedRows(storageKey: string): {\n expandedIds: Set<string>;\n toggle: (id: string) => void;\n isExpanded: (id: string) => boolean;\n} {\n const [expandedIds, setExpandedIds] = useState<Set<string>>(() => {\n try {\n const raw = localStorage.getItem(storageKey);\n if (raw) {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed)) return new Set(parsed);\n }\n } catch { /* corrupted or unavailable — start empty */ }\n return new Set();\n });\n\n const persist = useCallback((next: Set<string>) => {\n try {\n localStorage.setItem(storageKey, JSON.stringify([...next]));\n } catch { /* quota exceeded or unavailable — ignore */ }\n }, [storageKey]);\n\n const toggle = useCallback((id: string) => {\n setExpandedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n persist(next);\n return next;\n });\n }, [persist]);\n\n const isExpanded = useCallback((id: string) => expandedIds.has(id), [expandedIds]);\n\n return { expandedIds, toggle, isExpanded };\n}\n","import type { McpServerRecord, McpToolManifest } from '../../../api/types';\n\nexport function isBuiltIn(row: McpServerRecord): boolean {\n return !!(row.metadata as Record<string, unknown> | null)?.builtin\n || !!(row.transport_config as Record<string, unknown> | null)?.builtin;\n}\n\n/** Check if a server or any of its tools match the search term */\nexport function matchesSearch(server: McpServerRecord, search: string): boolean {\n if (!search) return true;\n const q = search.toLowerCase();\n if (server.name.toLowerCase().includes(q)) return true;\n if (server.description?.toLowerCase().includes(q)) return true;\n if ((server.tags ?? []).some((t) => t.toLowerCase().includes(q))) return true;\n const tools = (server.tool_manifest ?? []) as McpToolManifest[];\n return tools.some(\n (t) => t.name.toLowerCase().includes(q) || t.description?.toLowerCase().includes(q),\n );\n}\n\n/** Filter tools within a server that match the search term */\nexport function filterTools(tools: McpToolManifest[], search: string): McpToolManifest[] {\n if (!search) return tools;\n const q = search.toLowerCase();\n return tools.filter(\n (t) => t.name.toLowerCase().includes(q) || t.description?.toLowerCase().includes(q),\n );\n}\n","import { ChevronRight, Pencil, Trash2, Plug, Unplug, Play } from 'lucide-react';\nimport { RowAction, RowActionGroup } from '../../../components/common/layout/RowActions';\nimport {\n useConnectMcpServer,\n useDisconnectMcpServer,\n} from '../../../api/mcp';\nimport { StatusBadge } from '../../../components/common/display/StatusBadge';\nimport { ToolPill } from '../../../components/common/display/ToolPill';\nimport { ServerName } from '../../../components/common/display/ServerName';\n\nimport type { McpServerRecord, McpToolManifest } from '../../../api/types';\nimport { isBuiltIn } from './helpers';\n\nexport function ServerRow({\n server,\n expanded,\n onToggle,\n onEdit,\n onDelete,\n onTryTool,\n connect,\n disconnect,\n visibleTools,\n}: {\n server: McpServerRecord;\n expanded: boolean;\n onToggle: () => void;\n onEdit: () => void;\n onDelete: () => void;\n onTryTool: (tool: McpToolManifest) => void;\n connect: ReturnType<typeof useConnectMcpServer>;\n disconnect: ReturnType<typeof useDisconnectMcpServer>;\n visibleTools: McpToolManifest[];\n}) {\n const allTools = (server.tool_manifest ?? []) as McpToolManifest[];\n const builtin = isBuiltIn(server);\n const tags = server.tags ?? [];\n\n return (\n <>\n {/* Server header row */}\n <tr\n onClick={allTools.length > 0 ? onToggle : undefined}\n className={`group/row border-b border-surface-border/50 transition-colors duration-100 ${\n allTools.length > 0 ? 'cursor-pointer row-hover' : ''\n }`}\n >\n {/* Name + tags */}\n <td className=\"px-6 py-2.5\">\n <div className=\"flex items-center gap-3\">\n <span className={`transition-transform duration-150 ${expanded ? 'rotate-90' : ''} ${allTools.length === 0 ? 'opacity-0' : 'text-text-tertiary'}`}>\n <ChevronRight size={14} />\n </span>\n <span className=\"flex items-center gap-1.5\">\n <ServerName name={server.name} serverId={server.id} short={false} />\n {allTools.length > 0 && (\n <sup className=\"text-[9px] font-normal text-accent/70\">{allTools.length}</sup>\n )}\n </span>\n {tags.length > 0 && (\n <div className=\"flex gap-1 ml-auto shrink-0\">\n {tags.slice(0, 3).map((tag) => (\n <span key={tag} className=\"inline-block px-1.5 py-0 text-[9px] text-text-tertiary bg-surface-sunken rounded\">\n {tag}\n </span>\n ))}\n {tags.length > 3 && (\n <span className=\"text-[9px] text-text-quaternary\" title={tags.slice(3).join(', ')}>…</span>\n )}\n </div>\n )}\n </div>\n </td>\n\n {/* Status */}\n <td className=\"px-4 py-2.5 w-28 whitespace-nowrap\">\n <StatusBadge status={server.status} />\n </td>\n\n {/* Actions */}\n <td className=\"px-4 py-2.5 w-16\">\n <RowActionGroup>\n {!builtin && (\n server.status === 'connected' ? (\n <RowAction\n icon={Unplug}\n title=\"Disconnect server\"\n onClick={() => disconnect.mutate(server.id)}\n />\n ) : (\n <RowAction\n icon={Plug}\n title=\"Connect server\"\n onClick={() => connect.mutate(server.id)}\n colorClass=\"text-text-tertiary hover:text-status-success\"\n />\n )\n )}\n <RowAction\n icon={Pencil}\n title=\"Edit server\"\n onClick={onEdit}\n />\n {!builtin && (\n <RowAction\n icon={Trash2}\n title=\"Delete server\"\n onClick={onDelete}\n colorClass=\"text-text-tertiary hover:text-status-error\"\n />\n )}\n </RowActionGroup>\n </td>\n </tr>\n\n {/* Expanded tool rows — real table rows for column alignment */}\n {expanded && visibleTools.map((tool) => (\n <tr\n key={tool.name}\n onClick={() => onTryTool(tool)}\n className=\"group/row cursor-pointer hover:bg-surface-hover/50 transition-colors border-b border-surface-border/15\"\n >\n {/* Tool name + description */}\n <td className=\"pl-14 pr-6 py-2.5\">\n <ToolPill name={tool.name} size=\"md\" />\n {tool.description && (\n <p className=\"text-[11px] leading-snug text-text-quaternary mt-0.5\">{tool.description}</p>\n )}\n </td>\n\n {/* Status — empty for tools */}\n <td className=\"px-4 py-2.5 w-28\" />\n\n {/* Actions — play on hover */}\n <td className=\"px-4 py-2.5 w-16\">\n <div className=\"flex items-center justify-end\">\n <button\n onClick={(e) => { e.stopPropagation(); onTryTool(tool); }}\n className=\"opacity-0 group-hover/row:opacity-100 transition-opacity text-text-tertiary hover:text-accent\"\n title=\"Try tool\"\n >\n <Play className=\"w-3.5 h-3.5\" strokeWidth={1.5} />\n </button>\n </div>\n </td>\n </tr>\n ))}\n </>\n );\n}\n","import { useState, useMemo, useEffect } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n useMcpServers,\n useConnectMcpServer,\n useDisconnectMcpServer,\n useDeleteMcpServer,\n} from '../../../api/mcp';\nimport { EmptyState } from '../../../components/common/display/EmptyState';\nimport { ConfirmDeleteModal } from '../../../components/common/modal/ConfirmDeleteModal';\nimport type { McpServerRecord, McpToolManifest } from '../../../api/types';\nimport { PageHeader } from '../../../components/common/layout/PageHeader';\nimport { FilterBar, FilterSelect, FilterInput } from '../../../components/common/data/FilterBar';\nimport { StickyPagination } from '../../../components/common/data/StickyPagination';\nimport { useFilterParams } from '../../../hooks/useFilterParams';\nimport { useExpandedRows } from '../../../hooks/useExpandedRows';\nimport { ToolTestPanel } from '../../../components/common/test/ToolTestPanel';\nimport { matchesSearch, filterTools } from './helpers';\nimport { ServerRow } from './ServerRow';\n\nexport function McpServersPage() {\n const navigate = useNavigate();\n const { filters, setFilter, pagination } = useFilterParams({\n filters: { status: '', search: '', tag: '' },\n });\n\n const { data, isLoading } = useMcpServers({\n status: filters.status || undefined,\n search: filters.search || undefined,\n tags: filters.tag || undefined,\n });\n const connect = useConnectMcpServer();\n const disconnect = useDisconnectMcpServer();\n const deleteServer = useDeleteMcpServer();\n\n const [confirmDelete, setConfirmDelete] = useState<McpServerRecord | null>(null);\n const { expandedIds, toggle: toggleExpand } = useExpandedRows('lt:expanded:mcp-servers');\n const [tryTool, setTryTool] = useState<{\n serverId: string;\n serverName: string;\n tool: McpToolManifest;\n } | null>(null);\n\n const servers = data?.servers ?? [];\n const total = data?.total ?? 0;\n\n // Derive unique tags from current result set for the filter dropdown\n const tagOptions = useMemo(() => {\n const allTags = new Set<string>();\n for (const s of servers) {\n for (const t of s.tags ?? []) allTags.add(t);\n }\n return [...allTags].sort().map((t) => ({ value: t, label: t }));\n }, [servers]);\n\n // Client-side search filtering for tool-level matches within expanded rows\n const filteredServers = useMemo(() => {\n if (!filters.search) return servers;\n return servers.filter((s) => matchesSearch(s, filters.search));\n }, [servers, filters.search]);\n\n // Auto-expand servers whose tools match the search (so results are visible)\n useEffect(() => {\n if (!filters.search) return;\n const q = filters.search.toLowerCase();\n for (const s of filteredServers) {\n const tools = (s.tool_manifest ?? []) as McpToolManifest[];\n const hasToolMatch = tools.some(\n (t) => t.name.toLowerCase().includes(q) || t.description?.toLowerCase().includes(q),\n );\n if (hasToolMatch && !expandedIds.has(s.id)) {\n toggleExpand(s.id);\n }\n }\n }, [filters.search, filteredServers]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const handleDelete = () => {\n if (!confirmDelete) return;\n deleteServer.mutate(confirmDelete.id, {\n onSuccess: () => setConfirmDelete(null),\n });\n };\n\n if (isLoading) {\n return (\n <div>\n <PageHeader title=\"Servers & Tools\" />\n <div className=\"animate-pulse space-y-0\">\n {Array.from({ length: 5 }).map((_, i) => (\n <div key={i} className=\"h-14 border-b last:border-b-0 px-6 flex items-center\">\n <div className=\"h-3 bg-surface-sunken rounded w-full\" />\n </div>\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div>\n <PageHeader\n title=\"Servers & Tools\"\n docsHash=\"#docs:dashboard.md:mcp-server-tools\"\n actions={\n <button\n onClick={() => navigate('/mcp/servers/new')}\n className=\"btn-primary text-xs\"\n >\n Register Server\n </button>\n }\n />\n\n <p className=\"text-sm text-text-secondary mb-6 max-w-2xl leading-relaxed\">\n Registered MCP servers and their available tools. Each server exposes tools that can be used by the MCP Tool Designer.\n </p>\n\n <FilterBar>\n <FilterInput\n label=\"Search\"\n value={filters.search}\n onChange={(v) => setFilter('search', v)}\n placeholder=\"Server or tool name...\"\n />\n <FilterSelect\n label=\"Tag\"\n value={filters.tag}\n onChange={(v) => setFilter('tag', v)}\n options={tagOptions}\n />\n <FilterSelect\n label=\"Status\"\n value={filters.status}\n onChange={(v) => setFilter('status', v)}\n options={[\n { value: 'registered', label: 'Registered' },\n { value: 'connected', label: 'Connected' },\n { value: 'error', label: 'Error' },\n { value: 'disconnected', label: 'Disconnected' },\n ]}\n />\n </FilterBar>\n\n <div className={`flex gap-0 ${tryTool ? '' : ''}`}>\n {/* Server list */}\n <div className={`${tryTool ? 'flex-1 min-w-0' : 'w-full'} transition-all`}>\n {filteredServers.length === 0 ? (\n <EmptyState title=\"No servers found\" />\n ) : (\n <table className=\"w-full\">\n <thead>\n <tr className=\"border-b\">\n <th className=\"sticky top-[2.75rem] z-10 bg-surface px-6 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary\">\n Server / Tool\n </th>\n <th className=\"sticky top-[2.75rem] z-10 bg-surface px-4 py-3 text-left text-[10px] font-semibold uppercase tracking-widest text-text-tertiary w-28\">\n Status\n </th>\n <th className=\"sticky top-[2.75rem] z-10 bg-surface w-16\" />\n </tr>\n </thead>\n <tbody>\n {filteredServers.map((server) => (\n <ServerRow\n key={server.id}\n server={server}\n expanded={expandedIds.has(server.id)}\n onToggle={() => toggleExpand(server.id)}\n onEdit={() => navigate(`/mcp/servers/${server.id}`)}\n onDelete={() => setConfirmDelete(server)}\n onTryTool={(tool) =>\n setTryTool({\n serverId: server.id,\n serverName: server.name,\n tool,\n })\n }\n connect={connect}\n disconnect={disconnect}\n visibleTools={filterTools(\n (server.tool_manifest ?? []) as McpToolManifest[],\n filters.search,\n )}\n />\n ))}\n </tbody>\n </table>\n )}\n\n <StickyPagination\n page={pagination.page}\n totalPages={pagination.totalPages(total)}\n onPageChange={pagination.setPage}\n total={total}\n pageSize={pagination.pageSize}\n onPageSizeChange={pagination.setPageSize}\n />\n </div>\n\n {/* Test panel — slides in from right */}\n {tryTool && (\n <div className=\"w-[380px] shrink-0 sticky top-0 max-h-screen overflow-y-auto\">\n <ToolTestPanel\n serverId={tryTool.serverId}\n serverName={tryTool.serverName}\n tool={tryTool.tool}\n onClose={() => setTryTool(null)}\n />\n </div>\n )}\n </div>\n\n {/* Delete confirmation modal */}\n <ConfirmDeleteModal\n open={!!confirmDelete}\n onClose={() => setConfirmDelete(null)}\n onConfirm={handleDelete}\n title=\"Delete MCP Server\"\n description={\n <>\n Delete{' '}\n <span className=\"font-medium text-text-primary\">{confirmDelete?.name}</span>?\n This will remove the server registration.\n </>\n }\n isPending={deleteServer.isPending}\n error={deleteServer.error as Error | null}\n />\n </div>\n );\n}\n"],"names":["useExpandedRows","storageKey","expandedIds","setExpandedIds","useState","raw","parsed","persist","useCallback","next","toggle","id","prev","isExpanded","isBuiltIn","row","_a","_b","matchesSearch","server","search","q","t","filterTools","tools","ServerRow","expanded","onToggle","onEdit","onDelete","onTryTool","connect","disconnect","visibleTools","allTools","builtin","tags","jsxs","Fragment","jsx","ChevronRight","ServerName","tag","StatusBadge","RowActionGroup","RowAction","Unplug","Plug","Pencil","Trash2","tool","ToolPill","e","Play","McpServersPage","navigate","useNavigate","filters","setFilter","pagination","useFilterParams","data","isLoading","useMcpServers","useConnectMcpServer","useDisconnectMcpServer","deleteServer","useDeleteMcpServer","confirmDelete","setConfirmDelete","toggleExpand","tryTool","setTryTool","servers","total","tagOptions","useMemo","allTags","s","filteredServers","useEffect","handleDelete","PageHeader","_","i","FilterBar","FilterInput","v","FilterSelect","EmptyState","StickyPagination","ToolTestPanel","ConfirmDeleteModal"],"mappings":"s5BASO,SAASA,EAAgBC,EAI9B,CACA,KAAM,CAACC,EAAaC,CAAc,EAAIC,EAAAA,SAAsB,IAAM,CAChE,GAAI,CACF,MAAMC,EAAM,aAAa,QAAQJ,CAAU,EAC3C,GAAII,EAAK,CACP,MAAMC,EAAS,KAAK,MAAMD,CAAG,EAC7B,GAAI,MAAM,QAAQC,CAAM,EAAG,OAAO,IAAI,IAAIA,CAAM,CAClD,CACF,MAAQ,CAA+C,CACvD,WAAW,GACb,CAAC,EAEKC,EAAUC,cAAaC,GAAsB,CACjD,GAAI,CACF,aAAa,QAAQR,EAAY,KAAK,UAAU,CAAC,GAAGQ,CAAI,CAAC,CAAC,CAC5D,MAAQ,CAA+C,CACzD,EAAG,CAACR,CAAU,CAAC,EAETS,EAASF,cAAaG,GAAe,CACzCR,EAAgBS,GAAS,CACvB,MAAMH,EAAO,IAAI,IAAIG,CAAI,EACzB,OAAIH,EAAK,IAAIE,CAAE,EACbF,EAAK,OAAOE,CAAE,EAEdF,EAAK,IAAIE,CAAE,EAEbJ,EAAQE,CAAI,EACLA,CACT,CAAC,CACH,EAAG,CAACF,CAAO,CAAC,EAENM,EAAaL,cAAaG,GAAeT,EAAY,IAAIS,CAAE,EAAG,CAACT,CAAW,CAAC,EAEjF,MAAO,CAAE,YAAAA,EAAa,OAAAQ,EAAQ,WAAAG,CAAA,CAChC,CC7CO,SAASC,EAAUC,EAA+B,SACvD,MAAO,CAAC,GAAEC,EAAAD,EAAI,WAAJ,MAAAC,EAAiD,UACtD,CAAC,GAAEC,EAAAF,EAAI,mBAAJ,MAAAE,EAAyD,QACnE,CAGO,SAASC,GAAcC,EAAyBC,EAAyB,OAC9E,GAAI,CAACA,EAAQ,MAAO,GACpB,MAAMC,EAAID,EAAO,YAAA,EAGjB,OAFID,EAAO,KAAK,YAAA,EAAc,SAASE,CAAC,IACpCL,EAAAG,EAAO,cAAP,MAAAH,EAAoB,cAAc,SAASK,KAC1CF,EAAO,MAAQ,CAAA,GAAI,KAAMG,GAAMA,EAAE,YAAA,EAAc,SAASD,CAAC,CAAC,EAAU,IAC1DF,EAAO,eAAiB,CAAA,GAC1B,KACVG,GAAA,OAAM,OAAAA,EAAE,KAAK,cAAc,SAASD,CAAC,KAAKL,EAAAM,EAAE,cAAF,YAAAN,EAAe,cAAc,SAASK,IAAC,CAEtF,CAGO,SAASE,GAAYC,EAA0BJ,EAAmC,CACvF,GAAI,CAACA,EAAQ,OAAOI,EACpB,MAAMH,EAAID,EAAO,YAAA,EACjB,OAAOI,EAAM,OACVF,GAAA,OAAM,OAAAA,EAAE,KAAK,cAAc,SAASD,CAAC,KAAKL,EAAAM,EAAE,cAAF,YAAAN,EAAe,cAAc,SAASK,IAAC,CAEtF,CCdO,SAASI,GAAU,CACxB,OAAAN,EACA,SAAAO,EACA,SAAAC,EACA,OAAAC,EACA,SAAAC,EACA,UAAAC,EACA,QAAAC,EACA,WAAAC,EACA,aAAAC,CACF,EAUG,CACD,MAAMC,EAAYf,EAAO,eAAiB,CAAA,EACpCgB,EAAUrB,EAAUK,CAAM,EAC1BiB,EAAOjB,EAAO,MAAQ,CAAA,EAE5B,OACEkB,EAAAA,KAAAC,WAAA,CAEE,SAAA,CAAAD,EAAAA,KAAC,KAAA,CACC,QAASH,EAAS,OAAS,EAAIP,EAAW,OAC1C,UAAW,8EACTO,EAAS,OAAS,EAAI,2BAA6B,EACrD,GAGA,SAAA,CAAAK,EAAAA,IAAC,MAAG,UAAU,cACZ,SAAAF,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAE,MAAC,QAAK,UAAW,qCAAqCb,EAAW,YAAc,EAAE,IAAIQ,EAAS,SAAW,EAAI,YAAc,oBAAoB,GAC7I,eAACM,EAAA,CAAa,KAAM,GAAI,EAC1B,EACAH,EAAAA,KAAC,OAAA,CAAK,UAAU,4BACd,SAAA,CAAAE,EAAAA,IAACE,EAAA,CAAW,KAAMtB,EAAO,KAAM,SAAUA,EAAO,GAAI,MAAO,EAAA,CAAO,EACjEe,EAAS,OAAS,GACjBK,EAAAA,IAAC,OAAI,UAAU,wCAAyC,WAAS,MAAA,CAAO,CAAA,EAE5E,EACCH,EAAK,OAAS,GACbC,EAAAA,KAAC,MAAA,CAAI,UAAU,8BACZ,SAAA,CAAAD,EAAK,MAAM,EAAG,CAAC,EAAE,IAAKM,GACrBH,EAAAA,IAAC,OAAA,CAAe,UAAU,mFACvB,SAAAG,CAAA,EADQA,CAEX,CACD,EACAN,EAAK,OAAS,GACbG,EAAAA,IAAC,QAAK,UAAU,kCAAkC,MAAOH,EAAK,MAAM,CAAC,EAAE,KAAK,IAAI,EAAG,SAAA,GAAA,CAAQ,CAAA,CAAA,CAE/F,CAAA,CAAA,CAEJ,CAAA,CACF,EAGAG,EAAAA,IAAC,MAAG,UAAU,qCACZ,eAACI,EAAA,CAAY,OAAQxB,EAAO,MAAA,CAAQ,CAAA,CACtC,EAGAoB,MAAC,KAAA,CAAG,UAAU,mBACZ,gBAACK,EAAA,CACE,SAAA,CAAA,CAACT,IACAhB,EAAO,SAAW,YAChBoB,EAAAA,IAACM,EAAA,CACC,KAAMC,EACN,MAAM,oBACN,QAAS,IAAMd,EAAW,OAAOb,EAAO,EAAE,CAAA,CAAA,EAG5CoB,EAAAA,IAACM,EAAA,CACC,KAAME,EACN,MAAM,iBACN,QAAS,IAAMhB,EAAQ,OAAOZ,EAAO,EAAE,EACvC,WAAW,8CAAA,CAAA,GAIjBoB,EAAAA,IAACM,EAAA,CACC,KAAMG,EACN,MAAM,cACN,QAASpB,CAAA,CAAA,EAEV,CAACO,GACAI,EAAAA,IAACM,EAAA,CACC,KAAMI,EACN,MAAM,gBACN,QAASpB,EACT,WAAW,4CAAA,CAAA,CACb,CAAA,CAEJ,CAAA,CACF,CAAA,CAAA,CAAA,EAIDH,GAAYO,EAAa,IAAKiB,GAC7Bb,EAAAA,KAAC,KAAA,CAEC,QAAS,IAAMP,EAAUoB,CAAI,EAC7B,UAAU,yGAGV,SAAA,CAAAb,EAAAA,KAAC,KAAA,CAAG,UAAU,oBACZ,SAAA,CAAAE,EAAAA,IAACY,EAAA,CAAS,KAAMD,EAAK,KAAM,KAAK,KAAK,EACpCA,EAAK,aACJX,EAAAA,IAAC,KAAE,UAAU,uDAAwD,WAAK,WAAA,CAAY,CAAA,EAE1F,EAGAA,EAAAA,IAAC,KAAA,CAAG,UAAU,kBAAA,CAAmB,QAGhC,KAAA,CAAG,UAAU,mBACZ,SAAAA,MAAC,MAAA,CAAI,UAAU,gCACb,SAAAA,EAAAA,IAAC,SAAA,CACC,QAAUa,GAAM,CAAEA,EAAE,gBAAA,EAAmBtB,EAAUoB,CAAI,CAAG,EACxD,UAAU,gGACV,MAAM,WAEN,SAAAX,EAAAA,IAACc,EAAA,CAAK,UAAU,cAAc,YAAa,GAAA,CAAK,CAAA,CAAA,EAEpD,CAAA,CACF,CAAA,CAAA,EA1BKH,EAAK,IAAA,CA4Bb,CAAA,EACH,CAEJ,CCjIO,SAASI,IAAiB,CAC/B,MAAMC,EAAWC,EAAA,EACX,CAAE,QAAAC,EAAS,UAAAC,EAAW,WAAAC,CAAA,EAAeC,EAAgB,CACzD,QAAS,CAAE,OAAQ,GAAI,OAAQ,GAAI,IAAK,EAAA,CAAG,CAC5C,EAEK,CAAE,KAAAC,EAAM,UAAAC,CAAA,EAAcC,EAAc,CACxC,OAAQN,EAAQ,QAAU,OAC1B,OAAQA,EAAQ,QAAU,OAC1B,KAAMA,EAAQ,KAAO,MAAA,CACtB,EACK1B,EAAUiC,EAAA,EACVhC,EAAaiC,EAAA,EACbC,EAAeC,EAAA,EAEf,CAACC,EAAeC,CAAgB,EAAIjE,EAAAA,SAAiC,IAAI,EACzE,CAAE,YAAAF,EAAa,OAAQoE,CAAA,EAAiBtE,EAAgB,yBAAyB,EACjF,CAACuE,EAASC,CAAU,EAAIpE,EAAAA,SAIpB,IAAI,EAERqE,GAAUZ,GAAA,YAAAA,EAAM,UAAW,CAAA,EAC3Ba,GAAQb,GAAA,YAAAA,EAAM,QAAS,EAGvBc,EAAaC,EAAAA,QAAQ,IAAM,CAC/B,MAAMC,MAAc,IACpB,UAAWC,KAAKL,EACd,UAAWnD,KAAKwD,EAAE,MAAQ,CAAA,EAAID,EAAQ,IAAIvD,CAAC,EAE7C,MAAO,CAAC,GAAGuD,CAAO,EAAE,OAAO,IAAKvD,IAAO,CAAE,MAAOA,EAAG,MAAOA,GAAI,CAChE,EAAG,CAACmD,CAAO,CAAC,EAGNM,EAAkBH,EAAAA,QAAQ,IACzBnB,EAAQ,OACNgB,EAAQ,OAAQK,GAAM5D,GAAc4D,EAAGrB,EAAQ,MAAM,CAAC,EADjCgB,EAE3B,CAACA,EAAShB,EAAQ,MAAM,CAAC,EAG5BuB,EAAAA,UAAU,IAAM,CACd,GAAI,CAACvB,EAAQ,OAAQ,OACrB,MAAMpC,EAAIoC,EAAQ,OAAO,YAAA,EACzB,UAAWqB,KAAKC,GACCD,EAAE,eAAiB,CAAA,GACP,KACxBxD,GAAA,OAAM,OAAAA,EAAE,KAAK,cAAc,SAASD,CAAC,KAAKL,EAAAM,EAAE,cAAF,YAAAN,EAAe,cAAc,SAASK,IAAC,GAEhE,CAACnB,EAAY,IAAI4E,EAAE,EAAE,GACvCR,EAAaQ,EAAE,EAAE,CAGvB,EAAG,CAACrB,EAAQ,OAAQsB,CAAe,CAAC,EAEpC,MAAME,EAAe,IAAM,CACpBb,GACLF,EAAa,OAAOE,EAAc,GAAI,CACpC,UAAW,IAAMC,EAAiB,IAAI,CAAA,CACvC,CACH,EAEA,OAAIP,SAEC,MAAA,CACC,SAAA,CAAAvB,EAAAA,IAAC2C,EAAA,CAAW,MAAM,iBAAA,CAAkB,EACpC3C,EAAAA,IAAC,MAAA,CAAI,UAAU,0BACZ,SAAA,MAAM,KAAK,CAAE,OAAQ,CAAA,CAAG,EAAE,IAAI,CAAC4C,EAAGC,IACjC7C,EAAAA,IAAC,MAAA,CAAY,UAAU,uDACrB,SAAAA,EAAAA,IAAC,MAAA,CAAI,UAAU,sCAAA,CAAuC,CAAA,EAD9C6C,CAEV,CACD,CAAA,CACH,CAAA,EACF,SAKD,MAAA,CACC,SAAA,CAAA7C,EAAAA,IAAC2C,EAAA,CACC,MAAM,kBACN,SAAS,sCACT,QACE3C,EAAAA,IAAC,SAAA,CACC,QAAS,IAAMgB,EAAS,kBAAkB,EAC1C,UAAU,sBACX,SAAA,iBAAA,CAAA,CAED,CAAA,EAIJhB,EAAAA,IAAC,IAAA,CAAE,UAAU,6DAA6D,SAAA,yHAE1E,SAEC8C,EAAA,CACC,SAAA,CAAA9C,EAAAA,IAAC+C,EAAA,CACC,MAAM,SACN,MAAO7B,EAAQ,OACf,SAAW8B,GAAM7B,EAAU,SAAU6B,CAAC,EACtC,YAAY,wBAAA,CAAA,EAEdhD,EAAAA,IAACiD,EAAA,CACC,MAAM,MACN,MAAO/B,EAAQ,IACf,SAAW8B,GAAM7B,EAAU,MAAO6B,CAAC,EACnC,QAASZ,CAAA,CAAA,EAEXpC,EAAAA,IAACiD,EAAA,CACC,MAAM,SACN,MAAO/B,EAAQ,OACf,SAAW8B,GAAM7B,EAAU,SAAU6B,CAAC,EACtC,QAAS,CACP,CAAE,MAAO,aAAc,MAAO,YAAA,EAC9B,CAAE,MAAO,YAAa,MAAO,WAAA,EAC7B,CAAE,MAAO,QAAS,MAAO,OAAA,EACzB,CAAE,MAAO,eAAgB,MAAO,cAAA,CAAe,CACjD,CAAA,CACF,EACF,SAEC,MAAA,CAAI,UAAW,cAEd,SAAA,CAAAlD,OAAC,OAAI,UAAW,GAAGkC,EAAU,iBAAmB,QAAQ,kBACrD,SAAA,CAAAQ,EAAgB,SAAW,EAC1BxC,EAAAA,IAACkD,EAAA,CAAW,MAAM,mBAAmB,EAErCpD,EAAAA,KAAC,QAAA,CAAM,UAAU,SACf,SAAA,CAAAE,MAAC,QAAA,CACC,SAAAF,EAAAA,KAAC,KAAA,CAAG,UAAU,WACZ,SAAA,CAAAE,EAAAA,IAAC,KAAA,CAAG,UAAU,kIAAkI,SAAA,gBAEhJ,EACAA,EAAAA,IAAC,KAAA,CAAG,UAAU,uIAAuI,SAAA,SAErJ,EACAA,EAAAA,IAAC,KAAA,CAAG,UAAU,2CAAA,CAA4C,CAAA,CAAA,CAC5D,CAAA,CACF,EACAA,EAAAA,IAAC,QAAA,CACE,SAAAwC,EAAgB,IAAK5D,GACpBoB,EAAAA,IAACd,GAAA,CAEC,OAAAN,EACA,SAAUjB,EAAY,IAAIiB,EAAO,EAAE,EACnC,SAAU,IAAMmD,EAAanD,EAAO,EAAE,EACtC,OAAQ,IAAMoC,EAAS,gBAAgBpC,EAAO,EAAE,EAAE,EAClD,SAAU,IAAMkD,EAAiBlD,CAAM,EACvC,UAAY+B,GACVsB,EAAW,CACT,SAAUrD,EAAO,GACjB,WAAYA,EAAO,KACnB,KAAA+B,CAAA,CACD,EAEH,QAAAnB,EACA,WAAAC,EACA,aAAcT,GACXJ,EAAO,eAAiB,CAAA,EACzBsC,EAAQ,MAAA,CACV,EAlBKtC,EAAO,EAAA,CAoBf,CAAA,CACH,CAAA,EACF,EAGFoB,EAAAA,IAACmD,EAAA,CACC,KAAM/B,EAAW,KACjB,WAAYA,EAAW,WAAWe,CAAK,EACvC,aAAcf,EAAW,QACzB,MAAAe,EACA,SAAUf,EAAW,SACrB,iBAAkBA,EAAW,WAAA,CAAA,CAC/B,EACF,EAGCY,GACChC,EAAAA,IAAC,MAAA,CAAI,UAAU,+DACb,SAAAA,EAAAA,IAACoD,EAAA,CACC,SAAUpB,EAAQ,SAClB,WAAYA,EAAQ,WACpB,KAAMA,EAAQ,KACd,QAAS,IAAMC,EAAW,IAAI,CAAA,CAAA,CAChC,CACF,CAAA,EAEJ,EAGAjC,EAAAA,IAACqD,EAAA,CACC,KAAM,CAAC,CAACxB,EACR,QAAS,IAAMC,EAAiB,IAAI,EACpC,UAAWY,EACX,MAAM,oBACN,YACE5C,EAAAA,KAAAC,WAAA,CAAE,SAAA,CAAA,SACO,IACPC,EAAAA,IAAC,OAAA,CAAK,UAAU,gCAAiC,0BAAe,KAAK,EAAO,6CAAA,EAE9E,EAEF,UAAW2B,EAAa,UACxB,MAAOA,EAAa,KAAA,CAAA,CACtB,EACF,CAEJ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as i,j as e}from"./vendor-query-B2UbickB.js";import{P as oe}from"./PageHeader-DJo7yMUR.js";import{F as le,a as ce}from"./FilterBar-B4Mk2PvT.js";import{L as de}from"./ListToolbar-C_64Y22Z.js";import{S as xe}from"./StickyPagination-CeQCzVIA.js";import{E as Y}from"./EmptyState-BcsfPq9T.js";import{D as me}from"./DropZone-SgiK1WOl.js";import{T as _}from"./TimeAgo-BkyeBcMF.js";import{u as ue,a as pe,b as ne,c as he,d as fe,e as ie,f as ge}from"./knowledge-CTjJVvIG.js";import{T as je}from"./TagInput-CGGC3DTR.js";import{p as ye,X as be,l as Z,e as X,o as ee,D as te,aK as se}from"./vendor-icons-DOIDKgo6.js";import{a as Ne,f as ve}from"./vendor-react-CXumBFUA.js";import"./index-MbEPoyTe.js";function we(a){return a==null?"":typeof a=="string"?a:JSON.stringify(a,null,2)}function ae(a){const r=a.trim();if(!r)return{value:"",looksLikeJson:!1,parsedOk:!1};const o=r.startsWith("{")||r.startsWith("[");try{return{value:JSON.parse(r),looksLikeJson:o,parsedOk:!0}}catch{return{value:r,looksLikeJson:o,parsedOk:!1}}}function re(a){if(typeof a=="string"){const r=a.trim();return!(r.startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))}return typeof a=="number"||typeof a=="boolean"||a===null}function q({value:a,onChange:r,onKeyDown:o,placeholder:l,mono:d}){const x=i.useRef(null);return i.useEffect(()=>{x.current&&(x.current.style.height="auto",x.current.style.height=`${x.current.scrollHeight}px`,x.current.focus())},[a]),e.jsx("textarea",{ref:x,value:a,onChange:y=>r(y.target.value),onKeyDown:o,placeholder:l,rows:1,className:`w-full bg-transparent text-xs text-text-primary resize-none outline-none p-0 ${d?"font-mono":""}`,style:{minHeight:"1.5em"}})}function ke({domain:a,entryKey:r,onDeleted:o}){const{data:l,isLoading:d,refetch:x}=ue(a,r),y=pe(),m=ne(),F=he(),k=fe(),[S,K]=i.useState(!1),[u,f]=i.useState(null),[C,g]=i.useState(""),[j,E]=i.useState(""),[P,n]=i.useState(""),[A,O]=i.useState(null),[$,L]=i.useState(null),[J,b]=i.useState(!1),N=l==null?void 0:l.data,R=N?Object.entries(N):[],H=i.useMemo(()=>{const t=j.trim().toLowerCase();return t?R.filter(([h])=>h.toLowerCase().includes(t)):R},[R,j]),G=i.useCallback((t,h)=>h==="field"?t:we(N==null?void 0:N[t]),[N]),z=u?C!==G(u.field,u.column):!1;function M(t,h){f({field:t,column:h}),g(G(t,h)),O(null)}function T(){f(null),g("")}function s(){L("Invalid JSON — saved as text"),setTimeout(()=>L(null),4e3)}async function c(){if(!u||!N)return;const{field:t,column:h}=u;if(h==="value"){const{value:w,looksLikeJson:D,parsedOk:I}=ae(C);D&&!I&&s(),await F.mutateAsync({domain:a,key:r,path:t,value:w})}else{const w=C.trim();if(!w||w===t){T();return}const D=N[t];await k.mutateAsync({domain:a,key:r,path:t}),await F.mutateAsync({domain:a,key:r,path:w,value:D})}f(null),g(""),x()}async function v(t){await k.mutateAsync({domain:a,key:r,path:t}),O(null),f(null),x()}async function p(t){await m.mutateAsync({domain:a,key:r,data:N||{},tags:t,replace:!0}),x()}async function B(){const t=j.trim();if(!t)return;const{value:h,looksLikeJson:w,parsedOk:D}=ae(P);w&&!D&&s();const I={...N,[t]:h||""};await m.mutateAsync({domain:a,key:r,data:I}),E(""),n(""),x()}function U(t){t.key==="Escape"?T():t.key==="Enter"&&(t.metaKey||t.ctrlKey)&&(t.preventDefault(),c())}function Q(t){t.key==="Escape"?(E(""),n("")):t.key==="Enter"&&(t.metaKey||t.ctrlKey)&&(t.preventDefault(),B())}return d?e.jsxs("div",{className:"animate-pulse space-y-3 mt-4",children:[e.jsx("div",{className:"h-4 bg-surface-sunken rounded w-1/3"}),e.jsx("div",{className:"h-48 bg-surface-sunken rounded"})]}):!l||l.found===!1?e.jsx("p",{className:"text-sm text-text-tertiary mt-4",children:"Entry not found."}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsx("div",{className:"flex items-center gap-4 min-h-[28px]",children:J?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(je,{tags:l.tags||[],onChange:t=>{p(t)},placeholder:"Add tag...",compact:!0}),e.jsx("button",{onClick:()=>b(!1),className:"text-[10px] text-text-tertiary hover:text-text-secondary shrink-0",children:"Done"})]}):e.jsx("div",{className:"flex items-center gap-1 cursor-text group",onClick:()=>b(!0),title:"Click to edit tags",children:l.tags&&l.tags.length>0?l.tags.map(t=>e.jsx("span",{className:"inline-flex items-center px-2 py-0.5 rounded-full text-[10px] font-medium bg-accent/10 text-accent",children:t},t)):e.jsx("span",{className:"text-[10px] text-text-tertiary/40 italic group-hover:text-text-tertiary",children:"add tags..."})})}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"text-[10px] text-text-tertiary",children:e.jsx(_,{date:l.updated_at})}),S?e.jsxs("span",{className:"flex items-center gap-2 text-[10px]",children:[e.jsx("span",{className:"text-status-error",children:"Delete entry?"}),e.jsx("button",{onClick:async()=>{try{await y.mutateAsync({domain:a,key:r}),o()}catch{}},className:"font-medium text-status-error hover:text-status-error/80",disabled:y.isPending,children:y.isPending?"Deleting...":"Yes"}),e.jsx("button",{onClick:()=>K(!1),className:"text-text-tertiary hover:text-text-secondary",children:"No"})]}):e.jsx("button",{onClick:()=>K(!0),className:"text-text-tertiary/50 hover:text-status-error transition-colors",title:"Delete entry",children:e.jsx(ye,{className:"w-3.5 h-3.5"})})]})]}),$&&e.jsxs("div",{className:"flex items-center justify-end gap-2 mb-2 px-1",children:[e.jsx("span",{className:"inline-block w-1.5 h-1.5 rounded-full dot-ring bg-status-warning animate-pulse"}),e.jsx("span",{className:"text-xs text-status-warning",children:$})]}),e.jsxs("table",{className:"w-full border-collapse",children:[e.jsxs("thead",{className:"sticky top-0 z-10 bg-surface",children:[e.jsxs("tr",{className:"text-left text-[10px] uppercase tracking-wider text-text-tertiary border-b border-surface-border",children:[e.jsx("th",{className:"px-3 py-2 font-medium w-[200px] border-r border-surface-border",children:"Field"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Value"})]}),e.jsxs("tr",{className:"border-b border-surface-border bg-surface",children:[e.jsx("td",{className:"px-3 py-2 align-top border-r border-surface-border",children:e.jsx("input",{value:j,onChange:t=>E(t.target.value),onKeyDown:Q,placeholder:R.length?"add or filter...":"new field",className:"w-full bg-transparent text-xs text-text-primary placeholder:text-text-tertiary/40 placeholder:italic outline-none p-0"})}),e.jsxs("td",{className:"px-3 py-2 align-top",children:[e.jsx(q,{value:P,onChange:n,onKeyDown:Q,placeholder:"value"}),j.trim()&&e.jsxs("div",{className:"flex gap-2 mt-1.5",children:[e.jsx("button",{onClick:B,className:"text-[10px] font-medium text-accent hover:text-accent-hover",disabled:m.isPending,children:m.isPending?"Saving...":"Save"}),e.jsx("button",{onClick:()=>{E(""),n("")},className:"text-[10px] text-text-tertiary hover:text-text-secondary",children:"Cancel"})]})]})]})]}),e.jsx("tbody",{children:H.map(([t,h])=>{const w=(u==null?void 0:u.field)===t&&u.column==="field",D=(u==null?void 0:u.field)===t&&u.column==="value",I=w||D,W=A===t;return e.jsxs("tr",{className:`border-b border-surface-border ${W?"bg-status-error/10":I?"":"hover:bg-surface-hover/30"}`,children:[e.jsx("td",{className:`px-3 py-2 align-top border-r cursor-text ${W?"bg-transparent border-r-transparent":w?"border-r-surface-border bg-accent/5 border-l-2 border-l-accent":"border-r-surface-border"}`,onClick:()=>!w&&!W&&M(t,"field"),children:w?e.jsxs("div",{children:[e.jsx(q,{value:C,onChange:g,onKeyDown:U,placeholder:"field name"}),z&&e.jsxs("div",{className:"flex gap-2 mt-1.5",children:[e.jsx("button",{onClick:c,className:"text-[10px] font-medium text-accent hover:text-accent-hover",disabled:m.isPending,children:m.isPending?"Saving...":"Save"}),e.jsx("button",{onClick:T,className:"text-[10px] text-text-tertiary hover:text-text-secondary",children:"Cancel"})]})]}):e.jsx("span",{className:"text-xs font-medium text-text-secondary break-all",children:t})}),e.jsx("td",{className:`px-3 py-2 align-top cursor-text ${W?"bg-transparent":D?"bg-accent/5 border-l-2 border-l-accent":""}`,onClick:()=>!D&&!W&&M(t,"value"),children:W?e.jsxs("span",{className:"flex items-center justify-end gap-2 text-[10px]",children:[e.jsxs("span",{className:"text-status-error",children:["Remove ",e.jsx("span",{className:"font-medium",children:t}),"?"]}),e.jsx("button",{onClick:V=>{V.stopPropagation(),v(t)},className:"font-medium text-status-error hover:text-status-error/80",disabled:m.isPending,children:m.isPending?"...":"Yes"}),e.jsx("button",{onClick:V=>{V.stopPropagation(),O(null)},className:"text-text-tertiary hover:text-text-secondary",children:"No"})]}):D?e.jsxs("div",{children:[e.jsx(q,{value:C,onChange:g,onKeyDown:U,placeholder:"value (string or JSON)",mono:!re(h)}),e.jsxs("div",{className:"flex gap-2 mt-1.5",children:[z&&e.jsx("button",{onClick:c,className:"text-[10px] font-medium text-accent hover:text-accent-hover",disabled:m.isPending,children:m.isPending?"Saving...":"Save"}),e.jsx("button",{onClick:T,className:"text-[10px] text-text-tertiary hover:text-text-secondary",children:"Cancel"}),e.jsx("button",{onClick:V=>{V.stopPropagation(),O(t)},className:"text-[10px] text-status-error/50 hover:text-status-error ml-auto",children:"Remove"})]})]}):re(h)?e.jsx("p",{className:"text-xs text-text-primary break-words whitespace-pre-wrap",children:String(h)}):e.jsx("pre",{className:"text-xs text-text-primary font-mono whitespace-pre-wrap break-words",children:typeof h=="string"?h:JSON.stringify(h,null,2)})})]},t)})})]})]})}function Se({open:a,onClose:r,onCreated:o,prefillData:l,prefillDomain:d}){const{data:x}=ie(),y=ne(),[m,F]=i.useState(d||""),[k,S]=i.useState(""),[K,u]=i.useState(l?JSON.stringify(l,null,2):"{}"),[f,C]=i.useState(""),[g,j]=i.useState(""),E=((x==null?void 0:x.domains)??[]).map(n=>n.domain);if(i.useEffect(()=>{a&&(u(l?JSON.stringify(l,null,2):"{}"),F(d||""),S(""),C(""),j(""))},[a,l,d]),!a)return null;const P=async()=>{if(j(""),!m.trim()){j("Domain is required");return}if(!k.trim()){j("Key is required");return}let n;try{if(n=JSON.parse(K),typeof n!="object"||Array.isArray(n))throw new Error}catch{j("Data must be a valid JSON object");return}try{await y.mutateAsync({domain:m.trim(),key:k.trim(),data:n,tags:f?f.split(",").map(A=>A.trim()).filter(Boolean):[]}),o==null||o(m.trim(),k.trim()),r()}catch(A){j(A.message)}};return Ne.createPortal(e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"fixed inset-0 z-40 bg-black/30",onClick:r}),e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center p-6 overflow-y-auto",children:e.jsxs("div",{className:"bg-surface-raised border border-surface-border rounded-lg shadow-lg w-full max-w-md max-h-[85vh] flex flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between px-5 py-4 border-b border-surface-border",children:[e.jsx("h3",{className:"text-sm font-medium text-text-primary",children:"New Knowledge Entry"}),e.jsx("button",{onClick:r,className:"text-text-tertiary hover:text-text-primary",children:e.jsx(be,{className:"w-4 h-4"})})]}),e.jsxs("div",{className:"px-5 py-4 space-y-4 overflow-y-auto flex-1 min-h-0",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Domain"}),e.jsx("input",{type:"text",list:"domain-list",value:m,onChange:n=>F(n.target.value),placeholder:"e.g., screenshots, config, emails",className:"input text-xs w-full"}),e.jsx("datalist",{id:"domain-list",children:E.map(n=>e.jsx("option",{value:n},n))})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Key"}),e.jsx("input",{type:"text",value:k,onChange:n=>S(n.target.value),placeholder:"e.g., homepage, user-profile, report-2026",className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Data (JSON)"}),e.jsx("textarea",{value:K,onChange:n=>u(n.target.value),rows:8,className:"input-json w-full max-h-[30vh]"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Tags (comma-separated)"}),e.jsx("input",{type:"text",value:f,onChange:n=>C(n.target.value),placeholder:"e.g., important, review, 401k",className:"input text-xs w-full"})]}),g&&e.jsx("p",{className:"text-xs text-status-error",children:g})]}),e.jsxs("div",{className:"flex justify-end gap-2 px-5 py-3 border-t border-surface-border",children:[e.jsx("button",{onClick:r,className:"btn-ghost text-xs",children:"Cancel"}),e.jsx("button",{onClick:P,disabled:y.isPending,className:"btn-primary text-xs",children:y.isPending?"Creating...":"Create Entry"})]})]})})]}),document.body)}const Ce=50;function ze(){var z,M,T;const[a,r]=ve(),o=a.get("domain")||"",l=a.get("key")||"",[d,x]=i.useState(""),[y,m]=i.useState(""),[F,k]=i.useState(1),[S,K]=i.useState(Ce),[u,f]=i.useState(!1),[C,g]=i.useState(),j=i.useCallback(s=>{console.debug("[Knowledge] drop received:",s.map(p=>({name:p.name,type:p.type,size:p.size})));const c=s.find(p=>p.name.endsWith(".json")||p.type==="application/json");if(!c){console.warn("[Knowledge] no JSON file found in dropped files");return}console.debug("[Knowledge] reading:",c.name);const v=new FileReader;v.onload=()=>{try{const p=JSON.parse(v.result);typeof p=="object"&&!Array.isArray(p)?(console.debug("[Knowledge] parsed object with keys:",Object.keys(p)),g(p),f(!0)):console.warn("[Knowledge] JSON is not a plain object, got:",Array.isArray(p)?"array":typeof p)}catch(p){console.warn("[Knowledge] JSON parse failed:",p)}},v.readAsText(c)},[]);i.useEffect(()=>{const s=setTimeout(()=>{m(d),k(1)},300);return()=>clearTimeout(s)},[d]);const E=(F-1)*S,P=ie(),n=ge(o,{search:y||void 0,limit:S,offset:E}),A=((z=P.data)==null?void 0:z.domains)??[],O=((M=n.data)==null?void 0:M.entries)??[],$=((T=n.data)==null?void 0:T.total)??0,L=i.useMemo(()=>{if(!d)return A;const s=d.toLowerCase();return A.filter(c=>c.domain.toLowerCase().includes(s))},[A,d]);function J(s,c){x(""),m(""),k(1);const v={};s&&(v.domain=s),c&&(v.key=c),r(v)}const b=l?"entry":o?"entries":"domains",N=b==="entries"?n.isLoading:b==="domains"?P.isLoading:!1,R=Math.ceil((b==="entries"?$:L.length)/S),H=o?`/knowledge/entries?domain=${encodeURIComponent(o)}&limit=${S}&offset=${E}${y?`&search=${encodeURIComponent(y)}`:""}`:void 0;return e.jsxs(me,{onDrop:j,label:"Drop a JSON file to create an entry",accept:".json,application/json",children:[e.jsxs("div",{children:[e.jsx(oe,{title:"Knowledge",docsHash:"#docs:dashboard.md:knowledge",actions:e.jsxs("button",{onClick:()=>{g(void 0),f(!0)},className:"btn-primary text-xs inline-flex items-center gap-1.5",children:[e.jsx(Z,{className:"w-3.5 h-3.5"}),"New Entry"]})}),e.jsxs("nav",{className:"flex items-center gap-1 text-sm mb-6 min-h-[28px]",children:[e.jsxs("button",{onClick:()=>J(""),className:`flex items-center gap-1.5 px-1.5 py-0.5 rounded transition-colors ${b==="domains"?"text-text-primary font-medium":"text-text-secondary hover:text-text-primary hover:bg-surface-hover"}`,children:[e.jsx(X,{className:"w-4 h-4 text-accent/75",strokeWidth:1.5}),e.jsx("span",{children:"All Domains"})]}),o&&e.jsxs(e.Fragment,{children:[e.jsx(ee,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsxs("button",{onClick:()=>J(o),className:`flex items-center gap-1.5 px-1.5 py-0.5 rounded transition-colors ${b==="entries"?"text-text-primary font-medium":"text-text-secondary hover:text-text-primary hover:bg-surface-hover"}`,children:[e.jsx(te,{className:"w-3.5 h-3.5 text-accent/60",strokeWidth:1.5}),o]})]}),l&&e.jsxs(e.Fragment,{children:[e.jsx(ee,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsxs("span",{className:"flex items-center gap-1.5 px-1.5 py-0.5 text-text-primary font-medium",children:[e.jsx(se,{className:"w-3.5 h-3.5 text-accent/60",strokeWidth:1.5}),l]})]})]}),b==="entry"?e.jsx(ke,{domain:o,entryKey:l,onDeleted:()=>J(o)}):e.jsxs(e.Fragment,{children:[e.jsx(le,{actions:e.jsx(de,{onRefresh:()=>b==="entries"?n.refetch():P.refetch(),isFetching:b==="entries"?n.isFetching:P.isFetching,apiPath:b==="entries"?H:"/knowledge/domains"}),children:e.jsx(ce,{label:"Search",value:d,onChange:x,placeholder:o?"Filter by key or tag...":"Filter by domain..."})}),N?e.jsx("div",{className:"animate-pulse space-y-2 mt-4",children:Array.from({length:6}).map((s,c)=>e.jsx("div",{className:"h-10 bg-surface-sunken rounded"},c))}):b==="domains"?L.length===0?e.jsx("div",{className:"cursor-pointer",onClick:()=>{g(void 0),f(!0)},children:e.jsx(Y,{icon:X,title:d?"No matching domains":"No knowledge yet",description:d?void 0:"Create your first entry or drop a JSON file"})}):e.jsxs("table",{className:"w-full mt-2",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-[10px] uppercase tracking-wider text-text-tertiary",children:[e.jsx("th",{className:"pb-2 pl-2 font-medium",children:"Domain"}),e.jsx("th",{className:"pb-2 font-medium w-24 text-right",children:"Entries"}),e.jsx("th",{className:"pb-2 pr-2 font-medium w-40 text-right",children:"Latest"})]})}),e.jsx("tbody",{children:L.map(s=>e.jsxs("tr",{onClick:()=>J(s.domain),className:"row-hover cursor-pointer group",children:[e.jsx("td",{className:"py-2 pl-2",children:e.jsxs("span",{className:"flex items-center gap-2.5",children:[e.jsx(te,{className:"w-4 h-4 text-accent/75 shrink-0",strokeWidth:1.5}),e.jsx("span",{className:"text-sm text-text-primary group-hover:text-accent transition-colors",children:s.domain})]})}),e.jsx("td",{className:"py-2 text-right text-xs text-text-secondary tabular-nums",children:s.count}),e.jsx("td",{className:"py-2 pr-2 text-right text-xs text-text-secondary",children:e.jsx(_,{date:s.latest})})]},s.domain))})]}):O.length===0?e.jsx("div",{className:"cursor-pointer",onClick:()=>{g(void 0),f(!0)},children:e.jsx(Y,{icon:Z,title:d?"No matching entries":"No entries in this domain",description:d?void 0:"Add an entry or drop a JSON file"})}):e.jsxs(e.Fragment,{children:[e.jsxs("table",{className:"w-full mt-2",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-[10px] uppercase tracking-wider text-text-tertiary",children:[e.jsx("th",{className:"pb-2 pl-2 font-medium w-[200px]",children:"Key"}),e.jsx("th",{className:"pb-2 font-medium",children:"Tags"}),e.jsx("th",{className:"pb-2 font-medium w-16 text-right",children:"Fields"}),e.jsx("th",{className:"pb-2 pr-2 font-medium w-32 text-right",children:"Updated"})]})}),e.jsx("tbody",{children:O.map(s=>{var c;return e.jsxs("tr",{onClick:()=>J(o,s.key),className:"row-hover cursor-pointer group",children:[e.jsx("td",{className:"py-2 pl-2 w-[200px]",children:e.jsxs("span",{className:"flex items-center gap-2.5",children:[e.jsx(se,{className:"w-4 h-4 text-accent/75 shrink-0",strokeWidth:1.5}),e.jsx("span",{className:"text-sm text-text-primary group-hover:text-accent transition-colors truncate max-w-[160px]",title:s.key,children:s.key})]})}),e.jsx("td",{className:"py-2",children:e.jsxs("div",{className:"flex flex-wrap gap-1",children:[(c=s.tags)==null?void 0:c.slice(0,5).map(v=>e.jsx("span",{className:"inline-flex items-center px-1.5 py-0 rounded-full text-[10px] font-medium bg-accent/10 text-accent",children:v},v)),s.tags&&s.tags.length>5&&e.jsxs("span",{className:"text-[10px] text-text-tertiary",children:["+",s.tags.length-5]})]})}),e.jsx("td",{className:"py-2 text-right text-xs text-text-secondary tabular-nums",children:s.data?Object.keys(s.data).length:0}),e.jsx("td",{className:"py-2 pr-2 text-right text-xs text-text-secondary",children:e.jsx(_,{date:s.updated_at})})]},s.key)})})]}),e.jsx(xe,{page:F,totalPages:R,onPageChange:k,total:$,pageSize:S,onPageSizeChange:K})]})]})]}),e.jsx(Se,{open:u,onClose:()=>{f(!1),g(void 0)},onCreated:(s,c)=>{r({domain:s,key:c}),P.refetch()},prefillData:C,prefillDomain:o||void 0})]})}export{ze as KnowledgePage};
|
|
2
|
-
//# sourceMappingURL=index-
|
|
1
|
+
import{a as i,j as e}from"./vendor-query-B2UbickB.js";import{P as oe}from"./PageHeader-DJo7yMUR.js";import{F as le,a as ce}from"./FilterBar-B4Mk2PvT.js";import{L as de}from"./ListToolbar-Dz2_neVF.js";import{S as xe}from"./StickyPagination-CqT9Q1I6.js";import{E as Y}from"./EmptyState-BcsfPq9T.js";import{D as me}from"./DropZone-SgiK1WOl.js";import{T as _}from"./TimeAgo-C606LzT3.js";import{u as ue,a as pe,b as ne,c as he,d as fe,e as ie,f as ge}from"./knowledge-fYoEF4Lx.js";import{T as je}from"./TagInput-CGGC3DTR.js";import{p as ye,X as be,l as Z,e as X,o as ee,D as te,aK as se}from"./vendor-icons-DOIDKgo6.js";import{a as Ne,f as ve}from"./vendor-react-CXumBFUA.js";import"./index-DwWP-Z_c.js";function we(a){return a==null?"":typeof a=="string"?a:JSON.stringify(a,null,2)}function ae(a){const r=a.trim();if(!r)return{value:"",looksLikeJson:!1,parsedOk:!1};const o=r.startsWith("{")||r.startsWith("[");try{return{value:JSON.parse(r),looksLikeJson:o,parsedOk:!0}}catch{return{value:r,looksLikeJson:o,parsedOk:!1}}}function re(a){if(typeof a=="string"){const r=a.trim();return!(r.startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))}return typeof a=="number"||typeof a=="boolean"||a===null}function q({value:a,onChange:r,onKeyDown:o,placeholder:l,mono:d}){const x=i.useRef(null);return i.useEffect(()=>{x.current&&(x.current.style.height="auto",x.current.style.height=`${x.current.scrollHeight}px`,x.current.focus())},[a]),e.jsx("textarea",{ref:x,value:a,onChange:y=>r(y.target.value),onKeyDown:o,placeholder:l,rows:1,className:`w-full bg-transparent text-xs text-text-primary resize-none outline-none p-0 ${d?"font-mono":""}`,style:{minHeight:"1.5em"}})}function ke({domain:a,entryKey:r,onDeleted:o}){const{data:l,isLoading:d,refetch:x}=ue(a,r),y=pe(),m=ne(),F=he(),k=fe(),[S,K]=i.useState(!1),[u,f]=i.useState(null),[C,g]=i.useState(""),[j,E]=i.useState(""),[P,n]=i.useState(""),[A,O]=i.useState(null),[$,L]=i.useState(null),[J,b]=i.useState(!1),N=l==null?void 0:l.data,R=N?Object.entries(N):[],H=i.useMemo(()=>{const t=j.trim().toLowerCase();return t?R.filter(([h])=>h.toLowerCase().includes(t)):R},[R,j]),G=i.useCallback((t,h)=>h==="field"?t:we(N==null?void 0:N[t]),[N]),z=u?C!==G(u.field,u.column):!1;function M(t,h){f({field:t,column:h}),g(G(t,h)),O(null)}function T(){f(null),g("")}function s(){L("Invalid JSON — saved as text"),setTimeout(()=>L(null),4e3)}async function c(){if(!u||!N)return;const{field:t,column:h}=u;if(h==="value"){const{value:w,looksLikeJson:D,parsedOk:I}=ae(C);D&&!I&&s(),await F.mutateAsync({domain:a,key:r,path:t,value:w})}else{const w=C.trim();if(!w||w===t){T();return}const D=N[t];await k.mutateAsync({domain:a,key:r,path:t}),await F.mutateAsync({domain:a,key:r,path:w,value:D})}f(null),g(""),x()}async function v(t){await k.mutateAsync({domain:a,key:r,path:t}),O(null),f(null),x()}async function p(t){await m.mutateAsync({domain:a,key:r,data:N||{},tags:t,replace:!0}),x()}async function B(){const t=j.trim();if(!t)return;const{value:h,looksLikeJson:w,parsedOk:D}=ae(P);w&&!D&&s();const I={...N,[t]:h||""};await m.mutateAsync({domain:a,key:r,data:I}),E(""),n(""),x()}function U(t){t.key==="Escape"?T():t.key==="Enter"&&(t.metaKey||t.ctrlKey)&&(t.preventDefault(),c())}function Q(t){t.key==="Escape"?(E(""),n("")):t.key==="Enter"&&(t.metaKey||t.ctrlKey)&&(t.preventDefault(),B())}return d?e.jsxs("div",{className:"animate-pulse space-y-3 mt-4",children:[e.jsx("div",{className:"h-4 bg-surface-sunken rounded w-1/3"}),e.jsx("div",{className:"h-48 bg-surface-sunken rounded"})]}):!l||l.found===!1?e.jsx("p",{className:"text-sm text-text-tertiary mt-4",children:"Entry not found."}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsx("div",{className:"flex items-center gap-4 min-h-[28px]",children:J?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(je,{tags:l.tags||[],onChange:t=>{p(t)},placeholder:"Add tag...",compact:!0}),e.jsx("button",{onClick:()=>b(!1),className:"text-[10px] text-text-tertiary hover:text-text-secondary shrink-0",children:"Done"})]}):e.jsx("div",{className:"flex items-center gap-1 cursor-text group",onClick:()=>b(!0),title:"Click to edit tags",children:l.tags&&l.tags.length>0?l.tags.map(t=>e.jsx("span",{className:"inline-flex items-center px-2 py-0.5 rounded-full text-[10px] font-medium bg-accent/10 text-accent",children:t},t)):e.jsx("span",{className:"text-[10px] text-text-tertiary/40 italic group-hover:text-text-tertiary",children:"add tags..."})})}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"text-[10px] text-text-tertiary",children:e.jsx(_,{date:l.updated_at})}),S?e.jsxs("span",{className:"flex items-center gap-2 text-[10px]",children:[e.jsx("span",{className:"text-status-error",children:"Delete entry?"}),e.jsx("button",{onClick:async()=>{try{await y.mutateAsync({domain:a,key:r}),o()}catch{}},className:"font-medium text-status-error hover:text-status-error/80",disabled:y.isPending,children:y.isPending?"Deleting...":"Yes"}),e.jsx("button",{onClick:()=>K(!1),className:"text-text-tertiary hover:text-text-secondary",children:"No"})]}):e.jsx("button",{onClick:()=>K(!0),className:"text-text-tertiary/50 hover:text-status-error transition-colors",title:"Delete entry",children:e.jsx(ye,{className:"w-3.5 h-3.5"})})]})]}),$&&e.jsxs("div",{className:"flex items-center justify-end gap-2 mb-2 px-1",children:[e.jsx("span",{className:"inline-block w-1.5 h-1.5 rounded-full dot-ring bg-status-warning animate-pulse"}),e.jsx("span",{className:"text-xs text-status-warning",children:$})]}),e.jsxs("table",{className:"w-full border-collapse",children:[e.jsxs("thead",{className:"sticky top-0 z-10 bg-surface",children:[e.jsxs("tr",{className:"text-left text-[10px] uppercase tracking-wider text-text-tertiary border-b border-surface-border",children:[e.jsx("th",{className:"px-3 py-2 font-medium w-[200px] border-r border-surface-border",children:"Field"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Value"})]}),e.jsxs("tr",{className:"border-b border-surface-border bg-surface",children:[e.jsx("td",{className:"px-3 py-2 align-top border-r border-surface-border",children:e.jsx("input",{value:j,onChange:t=>E(t.target.value),onKeyDown:Q,placeholder:R.length?"add or filter...":"new field",className:"w-full bg-transparent text-xs text-text-primary placeholder:text-text-tertiary/40 placeholder:italic outline-none p-0"})}),e.jsxs("td",{className:"px-3 py-2 align-top",children:[e.jsx(q,{value:P,onChange:n,onKeyDown:Q,placeholder:"value"}),j.trim()&&e.jsxs("div",{className:"flex gap-2 mt-1.5",children:[e.jsx("button",{onClick:B,className:"text-[10px] font-medium text-accent hover:text-accent-hover",disabled:m.isPending,children:m.isPending?"Saving...":"Save"}),e.jsx("button",{onClick:()=>{E(""),n("")},className:"text-[10px] text-text-tertiary hover:text-text-secondary",children:"Cancel"})]})]})]})]}),e.jsx("tbody",{children:H.map(([t,h])=>{const w=(u==null?void 0:u.field)===t&&u.column==="field",D=(u==null?void 0:u.field)===t&&u.column==="value",I=w||D,W=A===t;return e.jsxs("tr",{className:`border-b border-surface-border ${W?"bg-status-error/10":I?"":"hover:bg-surface-hover/30"}`,children:[e.jsx("td",{className:`px-3 py-2 align-top border-r cursor-text ${W?"bg-transparent border-r-transparent":w?"border-r-surface-border bg-accent/5 border-l-2 border-l-accent":"border-r-surface-border"}`,onClick:()=>!w&&!W&&M(t,"field"),children:w?e.jsxs("div",{children:[e.jsx(q,{value:C,onChange:g,onKeyDown:U,placeholder:"field name"}),z&&e.jsxs("div",{className:"flex gap-2 mt-1.5",children:[e.jsx("button",{onClick:c,className:"text-[10px] font-medium text-accent hover:text-accent-hover",disabled:m.isPending,children:m.isPending?"Saving...":"Save"}),e.jsx("button",{onClick:T,className:"text-[10px] text-text-tertiary hover:text-text-secondary",children:"Cancel"})]})]}):e.jsx("span",{className:"text-xs font-medium text-text-secondary break-all",children:t})}),e.jsx("td",{className:`px-3 py-2 align-top cursor-text ${W?"bg-transparent":D?"bg-accent/5 border-l-2 border-l-accent":""}`,onClick:()=>!D&&!W&&M(t,"value"),children:W?e.jsxs("span",{className:"flex items-center justify-end gap-2 text-[10px]",children:[e.jsxs("span",{className:"text-status-error",children:["Remove ",e.jsx("span",{className:"font-medium",children:t}),"?"]}),e.jsx("button",{onClick:V=>{V.stopPropagation(),v(t)},className:"font-medium text-status-error hover:text-status-error/80",disabled:m.isPending,children:m.isPending?"...":"Yes"}),e.jsx("button",{onClick:V=>{V.stopPropagation(),O(null)},className:"text-text-tertiary hover:text-text-secondary",children:"No"})]}):D?e.jsxs("div",{children:[e.jsx(q,{value:C,onChange:g,onKeyDown:U,placeholder:"value (string or JSON)",mono:!re(h)}),e.jsxs("div",{className:"flex gap-2 mt-1.5",children:[z&&e.jsx("button",{onClick:c,className:"text-[10px] font-medium text-accent hover:text-accent-hover",disabled:m.isPending,children:m.isPending?"Saving...":"Save"}),e.jsx("button",{onClick:T,className:"text-[10px] text-text-tertiary hover:text-text-secondary",children:"Cancel"}),e.jsx("button",{onClick:V=>{V.stopPropagation(),O(t)},className:"text-[10px] text-status-error/50 hover:text-status-error ml-auto",children:"Remove"})]})]}):re(h)?e.jsx("p",{className:"text-xs text-text-primary break-words whitespace-pre-wrap",children:String(h)}):e.jsx("pre",{className:"text-xs text-text-primary font-mono whitespace-pre-wrap break-words",children:typeof h=="string"?h:JSON.stringify(h,null,2)})})]},t)})})]})]})}function Se({open:a,onClose:r,onCreated:o,prefillData:l,prefillDomain:d}){const{data:x}=ie(),y=ne(),[m,F]=i.useState(d||""),[k,S]=i.useState(""),[K,u]=i.useState(l?JSON.stringify(l,null,2):"{}"),[f,C]=i.useState(""),[g,j]=i.useState(""),E=((x==null?void 0:x.domains)??[]).map(n=>n.domain);if(i.useEffect(()=>{a&&(u(l?JSON.stringify(l,null,2):"{}"),F(d||""),S(""),C(""),j(""))},[a,l,d]),!a)return null;const P=async()=>{if(j(""),!m.trim()){j("Domain is required");return}if(!k.trim()){j("Key is required");return}let n;try{if(n=JSON.parse(K),typeof n!="object"||Array.isArray(n))throw new Error}catch{j("Data must be a valid JSON object");return}try{await y.mutateAsync({domain:m.trim(),key:k.trim(),data:n,tags:f?f.split(",").map(A=>A.trim()).filter(Boolean):[]}),o==null||o(m.trim(),k.trim()),r()}catch(A){j(A.message)}};return Ne.createPortal(e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"fixed inset-0 z-40 bg-black/30",onClick:r}),e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center p-6 overflow-y-auto",children:e.jsxs("div",{className:"bg-surface-raised border border-surface-border rounded-lg shadow-lg w-full max-w-md max-h-[85vh] flex flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between px-5 py-4 border-b border-surface-border",children:[e.jsx("h3",{className:"text-sm font-medium text-text-primary",children:"New Knowledge Entry"}),e.jsx("button",{onClick:r,className:"text-text-tertiary hover:text-text-primary",children:e.jsx(be,{className:"w-4 h-4"})})]}),e.jsxs("div",{className:"px-5 py-4 space-y-4 overflow-y-auto flex-1 min-h-0",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Domain"}),e.jsx("input",{type:"text",list:"domain-list",value:m,onChange:n=>F(n.target.value),placeholder:"e.g., screenshots, config, emails",className:"input text-xs w-full"}),e.jsx("datalist",{id:"domain-list",children:E.map(n=>e.jsx("option",{value:n},n))})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Key"}),e.jsx("input",{type:"text",value:k,onChange:n=>S(n.target.value),placeholder:"e.g., homepage, user-profile, report-2026",className:"input text-xs w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Data (JSON)"}),e.jsx("textarea",{value:K,onChange:n=>u(n.target.value),rows:8,className:"input-json w-full max-h-[30vh]"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] font-semibold uppercase tracking-widest text-text-tertiary mb-1",children:"Tags (comma-separated)"}),e.jsx("input",{type:"text",value:f,onChange:n=>C(n.target.value),placeholder:"e.g., important, review, 401k",className:"input text-xs w-full"})]}),g&&e.jsx("p",{className:"text-xs text-status-error",children:g})]}),e.jsxs("div",{className:"flex justify-end gap-2 px-5 py-3 border-t border-surface-border",children:[e.jsx("button",{onClick:r,className:"btn-ghost text-xs",children:"Cancel"}),e.jsx("button",{onClick:P,disabled:y.isPending,className:"btn-primary text-xs",children:y.isPending?"Creating...":"Create Entry"})]})]})})]}),document.body)}const Ce=50;function ze(){var z,M,T;const[a,r]=ve(),o=a.get("domain")||"",l=a.get("key")||"",[d,x]=i.useState(""),[y,m]=i.useState(""),[F,k]=i.useState(1),[S,K]=i.useState(Ce),[u,f]=i.useState(!1),[C,g]=i.useState(),j=i.useCallback(s=>{console.debug("[Knowledge] drop received:",s.map(p=>({name:p.name,type:p.type,size:p.size})));const c=s.find(p=>p.name.endsWith(".json")||p.type==="application/json");if(!c){console.warn("[Knowledge] no JSON file found in dropped files");return}console.debug("[Knowledge] reading:",c.name);const v=new FileReader;v.onload=()=>{try{const p=JSON.parse(v.result);typeof p=="object"&&!Array.isArray(p)?(console.debug("[Knowledge] parsed object with keys:",Object.keys(p)),g(p),f(!0)):console.warn("[Knowledge] JSON is not a plain object, got:",Array.isArray(p)?"array":typeof p)}catch(p){console.warn("[Knowledge] JSON parse failed:",p)}},v.readAsText(c)},[]);i.useEffect(()=>{const s=setTimeout(()=>{m(d),k(1)},300);return()=>clearTimeout(s)},[d]);const E=(F-1)*S,P=ie(),n=ge(o,{search:y||void 0,limit:S,offset:E}),A=((z=P.data)==null?void 0:z.domains)??[],O=((M=n.data)==null?void 0:M.entries)??[],$=((T=n.data)==null?void 0:T.total)??0,L=i.useMemo(()=>{if(!d)return A;const s=d.toLowerCase();return A.filter(c=>c.domain.toLowerCase().includes(s))},[A,d]);function J(s,c){x(""),m(""),k(1);const v={};s&&(v.domain=s),c&&(v.key=c),r(v)}const b=l?"entry":o?"entries":"domains",N=b==="entries"?n.isLoading:b==="domains"?P.isLoading:!1,R=Math.ceil((b==="entries"?$:L.length)/S),H=o?`/knowledge/entries?domain=${encodeURIComponent(o)}&limit=${S}&offset=${E}${y?`&search=${encodeURIComponent(y)}`:""}`:void 0;return e.jsxs(me,{onDrop:j,label:"Drop a JSON file to create an entry",accept:".json,application/json",children:[e.jsxs("div",{children:[e.jsx(oe,{title:"Knowledge",docsHash:"#docs:dashboard.md:knowledge",actions:e.jsxs("button",{onClick:()=>{g(void 0),f(!0)},className:"btn-primary text-xs inline-flex items-center gap-1.5",children:[e.jsx(Z,{className:"w-3.5 h-3.5"}),"New Entry"]})}),e.jsxs("nav",{className:"flex items-center gap-1 text-sm mb-6 min-h-[28px]",children:[e.jsxs("button",{onClick:()=>J(""),className:`flex items-center gap-1.5 px-1.5 py-0.5 rounded transition-colors ${b==="domains"?"text-text-primary font-medium":"text-text-secondary hover:text-text-primary hover:bg-surface-hover"}`,children:[e.jsx(X,{className:"w-4 h-4 text-accent/75",strokeWidth:1.5}),e.jsx("span",{children:"All Domains"})]}),o&&e.jsxs(e.Fragment,{children:[e.jsx(ee,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsxs("button",{onClick:()=>J(o),className:`flex items-center gap-1.5 px-1.5 py-0.5 rounded transition-colors ${b==="entries"?"text-text-primary font-medium":"text-text-secondary hover:text-text-primary hover:bg-surface-hover"}`,children:[e.jsx(te,{className:"w-3.5 h-3.5 text-accent/60",strokeWidth:1.5}),o]})]}),l&&e.jsxs(e.Fragment,{children:[e.jsx(ee,{className:"w-3.5 h-3.5 text-text-tertiary"}),e.jsxs("span",{className:"flex items-center gap-1.5 px-1.5 py-0.5 text-text-primary font-medium",children:[e.jsx(se,{className:"w-3.5 h-3.5 text-accent/60",strokeWidth:1.5}),l]})]})]}),b==="entry"?e.jsx(ke,{domain:o,entryKey:l,onDeleted:()=>J(o)}):e.jsxs(e.Fragment,{children:[e.jsx(le,{actions:e.jsx(de,{onRefresh:()=>b==="entries"?n.refetch():P.refetch(),isFetching:b==="entries"?n.isFetching:P.isFetching,apiPath:b==="entries"?H:"/knowledge/domains"}),children:e.jsx(ce,{label:"Search",value:d,onChange:x,placeholder:o?"Filter by key or tag...":"Filter by domain..."})}),N?e.jsx("div",{className:"animate-pulse space-y-2 mt-4",children:Array.from({length:6}).map((s,c)=>e.jsx("div",{className:"h-10 bg-surface-sunken rounded"},c))}):b==="domains"?L.length===0?e.jsx("div",{className:"cursor-pointer",onClick:()=>{g(void 0),f(!0)},children:e.jsx(Y,{icon:X,title:d?"No matching domains":"No knowledge yet",description:d?void 0:"Create your first entry or drop a JSON file"})}):e.jsxs("table",{className:"w-full mt-2",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-[10px] uppercase tracking-wider text-text-tertiary",children:[e.jsx("th",{className:"pb-2 pl-2 font-medium",children:"Domain"}),e.jsx("th",{className:"pb-2 font-medium w-24 text-right",children:"Entries"}),e.jsx("th",{className:"pb-2 pr-2 font-medium w-40 text-right",children:"Latest"})]})}),e.jsx("tbody",{children:L.map(s=>e.jsxs("tr",{onClick:()=>J(s.domain),className:"row-hover cursor-pointer group",children:[e.jsx("td",{className:"py-2 pl-2",children:e.jsxs("span",{className:"flex items-center gap-2.5",children:[e.jsx(te,{className:"w-4 h-4 text-accent/75 shrink-0",strokeWidth:1.5}),e.jsx("span",{className:"text-sm text-text-primary group-hover:text-accent transition-colors",children:s.domain})]})}),e.jsx("td",{className:"py-2 text-right text-xs text-text-secondary tabular-nums",children:s.count}),e.jsx("td",{className:"py-2 pr-2 text-right text-xs text-text-secondary",children:e.jsx(_,{date:s.latest})})]},s.domain))})]}):O.length===0?e.jsx("div",{className:"cursor-pointer",onClick:()=>{g(void 0),f(!0)},children:e.jsx(Y,{icon:Z,title:d?"No matching entries":"No entries in this domain",description:d?void 0:"Add an entry or drop a JSON file"})}):e.jsxs(e.Fragment,{children:[e.jsxs("table",{className:"w-full mt-2",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-[10px] uppercase tracking-wider text-text-tertiary",children:[e.jsx("th",{className:"pb-2 pl-2 font-medium w-[200px]",children:"Key"}),e.jsx("th",{className:"pb-2 font-medium",children:"Tags"}),e.jsx("th",{className:"pb-2 font-medium w-16 text-right",children:"Fields"}),e.jsx("th",{className:"pb-2 pr-2 font-medium w-32 text-right",children:"Updated"})]})}),e.jsx("tbody",{children:O.map(s=>{var c;return e.jsxs("tr",{onClick:()=>J(o,s.key),className:"row-hover cursor-pointer group",children:[e.jsx("td",{className:"py-2 pl-2 w-[200px]",children:e.jsxs("span",{className:"flex items-center gap-2.5",children:[e.jsx(se,{className:"w-4 h-4 text-accent/75 shrink-0",strokeWidth:1.5}),e.jsx("span",{className:"text-sm text-text-primary group-hover:text-accent transition-colors truncate max-w-[160px]",title:s.key,children:s.key})]})}),e.jsx("td",{className:"py-2",children:e.jsxs("div",{className:"flex flex-wrap gap-1",children:[(c=s.tags)==null?void 0:c.slice(0,5).map(v=>e.jsx("span",{className:"inline-flex items-center px-1.5 py-0 rounded-full text-[10px] font-medium bg-accent/10 text-accent",children:v},v)),s.tags&&s.tags.length>5&&e.jsxs("span",{className:"text-[10px] text-text-tertiary",children:["+",s.tags.length-5]})]})}),e.jsx("td",{className:"py-2 text-right text-xs text-text-secondary tabular-nums",children:s.data?Object.keys(s.data).length:0}),e.jsx("td",{className:"py-2 pr-2 text-right text-xs text-text-secondary",children:e.jsx(_,{date:s.updated_at})})]},s.key)})})]}),e.jsx(xe,{page:F,totalPages:R,onPageChange:k,total:$,pageSize:S,onPageSizeChange:K})]})]})]}),e.jsx(Se,{open:u,onClose:()=>{f(!1),g(void 0)},onCreated:(s,c)=>{r({domain:s,key:c}),P.refetch()},prefillData:C,prefillDomain:o||void 0})]})}export{ze as KnowledgePage};
|
|
2
|
+
//# sourceMappingURL=index-C7VXLKJs.js.map
|