@sparkelf/dsh-client-ui-skill-center 0.2.1-rc.2.4 → 0.2.2-alpha.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -8,7 +8,7 @@ window.__ModuleLoader__.load({
8
8
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
9
  let react_jsx_runtime = require("react/jsx-runtime");
10
10
  //#region \0dsh-css:/root/projects/deepseek-harness-plus/packages/plus/ui-skill-center/src/client/SkillCenterPage.module.css.mjs
11
- const css = ".DGiSta_page{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);flex-direction:column;align-items:center;gap:16px;padding:24px clamp(24px,4vw,40px) 40px;display:flex;overflow:auto}.DGiSta_page>*{width:100%;max-width:960px}.DGiSta_pageHead{justify-content:space-between;align-items:center;gap:16px;display:flex}.DGiSta_pageTitle{margin:0;font-size:20px;font-weight:500;line-height:28px}.DGiSta_toolbar{justify-content:flex-end;align-items:center;gap:16px;display:flex}.DGiSta_iconButton{width:28px;height:28px;color:var(--dsw-alias-label-caption);cursor:pointer;background:0 0;border:0;border-radius:28px;justify-content:center;align-items:center;display:inline-flex}.DGiSta_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.DGiSta_iconButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.DGiSta_iconWrap{display:inline-flex}.DGiSta_search{width:100%}.DGiSta_group{min-width:0}.DGiSta_groupTitle{align-items:baseline;gap:8px;margin:0 0 8px;font-size:14px;font-weight:500;line-height:20px;display:flex}.DGiSta_groupCount{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400}.DGiSta_cards{grid-template-columns:repeat(auto-fill,minmax(272px,1fr));align-items:start;gap:12px;margin:0;padding:0;list-style:none;display:grid}.DGiSta_card{border:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:10px;flex-direction:column;align-self:start;gap:10px;min-width:0;padding:12px;display:flex}.DGiSta_cardHead{align-items:center;gap:10px;min-width:0;display:flex}.DGiSta_cardIcon{corner-shape:round;background:var(--dsw-alias-bg-layer-2);width:28px;height:28px;color:var(--dsw-alias-label-secondary);border-radius:50%;flex:none;place-items:center;display:grid}.DGiSta_cardForeign{opacity:.72}.DGiSta_workspaceBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);vertical-align:middle;border-radius:4px;margin-left:8px;padding:1px 6px;font-size:11px;font-weight:400;line-height:16px}.DGiSta_cardTitle{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;overflow:hidden}.DGiSta_cardTitleRow{flex:1;align-items:center;gap:8px;min-width:0;display:flex}.DGiSta_cardMarks{flex-wrap:wrap;gap:6px;margin-top:2px;display:flex}.DGiSta_mark{color:var(--dsw-alias-state-business-primary);white-space:nowrap;background:#ecf1fc;border:0;border-radius:4px;padding:2px 7px;font-size:11px;font-weight:500;line-height:16px}.DGiSta_markOff,.DGiSta_markDanger{background:#ecf1fc}.DGiSta_detail{flex-direction:column;gap:12px;margin:0;display:flex}.DGiSta_cardActions{flex:none;align-items:center;gap:4px;display:inline-flex}.DGiSta_detailRow{flex-direction:column;gap:2px;display:flex}.DGiSta_detailLabel{color:var(--dsw-alias-label-caption);font-size:11px;line-height:16px}.DGiSta_detailValue{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:12px;line-height:18px}.DGiSta_cardEnd{flex:none;justify-content:space-between;align-items:center;gap:8px;margin-top:auto;padding-top:2px;display:flex}.DGiSta_cardBody{flex-direction:column;gap:6px;min-width:0;display:flex}.DGiSta_switch{background:var(--dsw-alias-border-l3);cursor:pointer;border:none;border-radius:10px;width:36px;height:20px;transition:background .12s;position:relative}.DGiSta_switch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.DGiSta_switchOn{background:var(--dsw-alias-state-success-primary)}.DGiSta_switch:after{content:\"\";corner-shape:round;background:var(--dsw-alias-bg-layer-1);border-radius:50%;width:16px;height:16px;transition:transform .12s;position:absolute;top:2px;left:2px}.DGiSta_switchOn:after{transform:translate(16px)}.DGiSta_dialog{width:min(560px,100%)}.DGiSta_form{flex-direction:column;gap:12px;display:flex}.DGiSta_field{flex-direction:column;gap:4px;display:flex}.DGiSta_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.DGiSta_input{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);height:32px;color:var(--dsw-alias-label-primary);background:0 0;border-radius:8px;padding:0 10px;font-size:13px}.DGiSta_textarea{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);min-height:80px;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-markdown-code-block-small);resize:vertical;background:0 0;border-radius:8px;padding:8px 10px;font-size:12px}.DGiSta_status{text-align:center;color:var(--dsw-alias-label-tertiary);padding:32px 0;font-size:13px}.DGiSta_statusError{color:var(--dsw-alias-state-error-primary)}.DGiSta_cardSummary{color:var(--dsw-alias-label-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:18px;display:-webkit-box;overflow:hidden}.DGiSta_body{flex-direction:column;gap:4px;min-width:0;margin-top:16px;display:flex}.DGiSta_bodyLabel{color:var(--dsw-alias-label-caption);margin:0;font-size:11px;font-weight:500;line-height:16px}.DGiSta_bodyPre{background:var(--dsw-alias-markdown-code-block);max-height:46vh;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-markdown-code-block-small-font-family);font-size:var(--dsw-font-markdown-code-block-small-font-size);line-height:var(--dsw-font-markdown-code-block-small-line-height);white-space:pre-wrap;overflow-wrap:anywhere;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:8px;margin:0;padding:12px;overflow:auto}.DGiSta_bodyStatus{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.DGiSta_bodyError{color:var(--dsw-alias-state-error-primary);}.DGiSta_progressRow{align-items:center;gap:8px;margin-bottom:12px;display:flex}.DGiSta_progressLabel{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:12px;line-height:18px}.DGiSta_progressTrack{background:var(--dsw-alias-border-l2);border-radius:2px;flex:1;height:4px;overflow:hidden}.DGiSta_progressFill{background:var(--dsw-alias-label-primary);border-radius:2px;height:100%;transition:width .2s;display:block}.DGiSta_progressCount{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:18px}";
11
+ const css = ".DGiSta_page{box-sizing:border-box;width:100%;height:100%;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);padding:0 0 48px;overflow:auto}.DGiSta_pageContent{width:100%;max-width:960px;margin:0 auto;padding:0 clamp(24px,4vw,48px)}.DGiSta_pageHead{justify-content:space-between;align-items:center;gap:16px;margin-bottom:24px;padding-top:28px;display:flex}.DGiSta_pageTitle{margin:0;font-size:20px;font-weight:500;line-height:28px}.DGiSta_toolbar{justify-content:flex-end;align-items:center;gap:16px;display:flex}.DGiSta_iconButton{width:28px;height:28px;color:var(--dsw-alias-label-caption);cursor:pointer;background:0 0;border:0;border-radius:28px;justify-content:center;align-items:center;display:inline-flex}.DGiSta_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.DGiSta_iconButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.DGiSta_iconWrap{display:inline-flex}.DGiSta_tabs{flex-wrap:wrap;align-items:center;gap:8px 12px;margin-bottom:14px;display:flex}.DGiSta_tab{height:28px;color:var(--dsw-alias-label-tertiary);font:inherit;white-space:nowrap;cursor:pointer;background:0 0;border:0;border-radius:14px;flex:none;align-items:center;gap:6px;padding:0 10px;font-size:14px;line-height:22px;display:inline-flex}@media (hover:hover){.DGiSta_tab:hover{background:var(--dsw-alias-interactive-bg-hover)}}.DGiSta_tab:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:2px}.DGiSta_tabActive{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.DGiSta_tabCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:18px}.DGiSta_tabActive .DGiSta_tabCount{color:var(--dsw-alias-label-secondary)}.DGiSta_searchField{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);width:100%;height:36px;color:var(--dsw-alias-label-tertiary);border-radius:12px;align-items:center;gap:4px;margin:0 0 16px;padding:0 10px;transition:border-color .15s;display:flex}@media (hover:hover){.DGiSta_searchField:hover{border-color:var(--dsw-alias-border-l2)}}.DGiSta_searchField:focus-within{border-color:var(--dsw-alias-state-business-primary)}.DGiSta_searchField>:first-child{background:0 0;border:0;border-radius:0;flex:1;min-width:0;height:100%;padding:0}.DGiSta_searchField>:first-child:focus-within{border-color:#0000}.DGiSta_searchField>:first-child svg{width:14px;height:14px}.DGiSta_searchField input::placeholder{color:var(--dsw-alias-label-caption)}.DGiSta_searchField input:focus-visible{outline:none}.DGiSta_searchField input::-webkit-search-cancel-button{display:none}.DGiSta_searchClear{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);flex:none;margin-right:-6px;padding:0}.DGiSta_tabPanel,.DGiSta_plazaPanel,.DGiSta_group{min-width:0}.DGiSta_groupTitle{align-items:baseline;gap:8px;margin:0 0 8px;font-size:14px;font-weight:500;line-height:20px;display:flex}.DGiSta_groupCount{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400}.DGiSta_cards{grid-template-columns:repeat(auto-fill,minmax(272px,1fr));align-content:start;align-items:stretch;gap:12px;margin:0;padding:0;list-style:none;display:grid}.DGiSta_card{border:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:10px;flex-direction:column;gap:10px;min-width:0;min-height:0;padding:12px;display:flex}.DGiSta_cardHead{align-items:center;gap:10px;min-width:0;display:flex}.DGiSta_cardIcon{corner-shape:round;background:var(--dsw-alias-bg-layer-2);width:28px;height:28px;color:var(--dsw-alias-label-secondary);border-radius:50%;flex:none;place-items:center;display:grid}.DGiSta_cardForeign{opacity:.72}.DGiSta_workspaceBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);vertical-align:middle;border-radius:4px;margin-left:8px;padding:1px 6px;font-size:11px;font-weight:400;line-height:16px}.DGiSta_cardTitle{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;overflow:hidden}.DGiSta_cardTitleRow{flex:1;align-items:center;gap:8px;min-width:0;min-height:26px;display:flex}.DGiSta_cardMarks{flex-wrap:wrap;gap:6px;min-height:18px;margin-top:2px;display:flex}.DGiSta_mark{color:var(--dsw-alias-state-business-primary);white-space:nowrap;background:#ecf1fc;border:0;border-radius:4px;padding:2px 7px;font-size:11px;font-weight:500;line-height:16px}.DGiSta_markOff,.DGiSta_markDanger{background:#ecf1fc}.DGiSta_detail{flex-direction:column;gap:12px;margin:0;display:flex}.DGiSta_cardActions{flex:none;align-items:center;gap:4px;display:inline-flex}.DGiSta_cardActions button{border-radius:6px;justify-content:center;align-items:center;height:28px;min-height:28px;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.DGiSta_detailRow{flex-direction:column;gap:2px;display:flex}.DGiSta_detailLabel{color:var(--dsw-alias-label-caption);font-size:11px;line-height:16px}.DGiSta_detailValue{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:12px;line-height:18px}.DGiSta_cardEnd{flex:none;justify-content:space-between;align-items:center;gap:8px;margin-top:auto;padding-top:2px;display:flex}.DGiSta_cardBody{flex-direction:column;gap:6px;min-width:0;display:flex}.DGiSta_switch{background:var(--dsw-alias-border-l3);cursor:pointer;border:none;border-radius:10px;width:36px;height:20px;transition:background .12s;position:relative}.DGiSta_switch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.DGiSta_switchOn{background:var(--dsw-alias-state-success-primary)}.DGiSta_switch:after{content:\"\";corner-shape:round;background:var(--dsw-alias-bg-layer-1);border-radius:50%;width:16px;height:16px;transition:transform .12s;position:absolute;top:2px;left:2px}.DGiSta_switchOn:after{transform:translate(16px)}.DGiSta_dialog{color-scheme:light;width:min(560px,100%)}body[data-ds-dark-theme] .DGiSta_dialog{color-scheme:dark}.DGiSta_publishDialog.DGiSta_publishDialog{color-scheme:light;gap:0;width:min(720px,100vw - 32px);max-width:100%;max-height:min(82vh,760px);padding:0 0 20px}body[data-ds-dark-theme] .DGiSta_publishDialog.DGiSta_publishDialog{color-scheme:dark}.DGiSta_dialogHeader{flex:none;justify-content:space-between;align-items:center;gap:8px;padding:22px 24px 12px;display:flex}.DGiSta_dialogTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.DGiSta_dialogClose{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;flex:none;justify-content:center;align-items:center;display:inline-flex}.DGiSta_dialogClose:hover{background:var(--dsw-alias-interactive-bg-hover)}.DGiSta_dialogClose:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:2px}.DGiSta_dialogBody{overscroll-behavior:contain;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);flex:1;min-height:0;padding:0 24px;overflow-y:auto}.DGiSta_dialogFooter{flex:none;justify-content:flex-end;align-items:center;gap:8px;padding:16px 24px 0;display:flex}.DGiSta_dialogBody .DGiSta_textarea{min-height:200px}.DGiSta_form{flex-direction:column;gap:12px;display:flex}.DGiSta_field{flex-direction:column;gap:4px;display:flex}.DGiSta_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.DGiSta_input{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);height:32px;color:var(--dsw-alias-label-primary);accent-color:var(--dsw-alias-state-business-primary);background:0 0;border-radius:8px;padding:0 10px;font-size:13px}.DGiSta_input:hover:not(:disabled){border-color:var(--dsw-alias-border-l2)}.DGiSta_input:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px;border-color:var(--dsw-alias-state-business-primary)}.DGiSta_input:disabled{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-secondary);cursor:default}.DGiSta_input option{background-color:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}.DGiSta_input option:disabled{color:var(--dsw-alias-label-caption)}.DGiSta_textarea{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);min-height:80px;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-markdown-code-block-small);resize:vertical;background:0 0;border-radius:8px;padding:8px 10px;font-size:12px}.DGiSta_status{text-align:center;color:var(--dsw-alias-label-tertiary);padding:32px 0;font-size:13px}.DGiSta_statusError{color:var(--dsw-alias-state-error-primary)}.DGiSta_cardSummary{color:var(--dsw-alias-label-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;min-height:36px;font-size:12px;line-height:18px;display:-webkit-box;overflow:hidden}.DGiSta_body{flex-direction:column;gap:4px;min-width:0;margin-top:16px;display:flex}.DGiSta_bodyLabel{color:var(--dsw-alias-label-caption);margin:0;font-size:11px;font-weight:500;line-height:16px}.DGiSta_bodyPre{background:var(--dsw-alias-markdown-code-block);max-height:46vh;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-markdown-code-block-small-font-family);font-size:var(--dsw-font-markdown-code-block-small-font-size);line-height:var(--dsw-font-markdown-code-block-small-line-height);white-space:pre-wrap;overflow-wrap:anywhere;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:8px;margin:0;padding:12px;overflow:auto}.DGiSta_bodyStatus{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.DGiSta_bodyError{color:var(--dsw-alias-state-error-primary);}.DGiSta_progressRow{align-items:center;gap:8px;margin-bottom:12px;display:flex}.DGiSta_progressLabel{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:12px;line-height:18px}.DGiSta_progressTrack{background:var(--dsw-alias-border-l2);border-radius:2px;flex:1;height:4px;overflow:hidden}.DGiSta_progressFill{background:var(--dsw-alias-label-primary);border-radius:2px;height:100%;transition:width .2s;display:block}.DGiSta_progressCount{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:18px}.DGiSta_plazaBadge{white-space:nowrap;border:.5px solid var(--dsw-alias-border-l2);border-radius:4px;flex:none;padding:0 6px;font-size:11px;line-height:18px}.DGiSta_plazaBadgeLocal{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-secondary)}.DGiSta_plazaBadgePending,.DGiSta_plazaBadgeApproved{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-secondary)}.DGiSta_plazaBadgeRejected{color:var(--dsw-alias-label-error);background:var(--dsw-alias-bg-secondary)}.DGiSta_plazaSharedTag{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-secondary);border-radius:4px;flex:none;padding:0 6px;font-size:11px;line-height:18px}.DGiSta_plazaReason{color:var(--dsw-alias-label-error);margin-top:4px;font-size:12px;line-height:18px}.DGiSta_plazaScopeHint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.DGiSta_connectorTab{flex-direction:column;gap:12px;min-width:0;display:flex}.DGiSta_connectorDemoNote{background:var(--dsw-specific-sidebar-fill);color:var(--dsw-alias-label-secondary);border-radius:10px;align-items:center;gap:8px;padding:9px 12px;font-size:12px;line-height:18px;display:flex}.DGiSta_connectorDemoTag{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-tertiary);border-radius:4px;flex:none;padding:0 6px;font-size:11px;line-height:18px}.DGiSta_connectorGrid{grid-template-columns:repeat(auto-fill,minmax(320px,1fr));align-items:start;gap:12px;display:grid}.DGiSta_connectorCard{border:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:12px;flex-direction:column;gap:10px;min-width:0;padding:14px;display:flex}.DGiSta_connectorHead{align-items:center;gap:10px;min-width:0;display:flex}.DGiSta_connectorIcon{background:var(--dsw-alias-bg-module-platform);width:32px;height:32px;color:var(--dsw-alias-state-business-primary);border-radius:9px;flex:none;place-items:center;display:grid}.DGiSta_connectorIdentity{flex:1;min-width:0}.DGiSta_connectorName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;overflow:hidden}.DGiSta_connectorVendor{color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:11px;line-height:16px}.DGiSta_connectorDescription{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:18px}.DGiSta_connectorError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.DGiSta_connectorToggleRow{justify-content:space-between;align-items:center;gap:12px;min-height:28px;display:flex}.DGiSta_connectorToggleLabel{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.DGiSta_capabilityList{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:2px;padding-top:10px;display:flex}.DGiSta_capabilityTitle{color:var(--dsw-alias-label-tertiary);margin-bottom:4px;font-size:11px;line-height:16px}.DGiSta_capabilityRow{justify-content:space-between;align-items:center;gap:12px;min-height:44px;padding:6px 0;display:flex}.DGiSta_capabilityRow+.DGiSta_capabilityRow{border-top:.5px solid var(--dsw-alias-border-l1)}.DGiSta_capabilityCopy{flex:1;min-width:0}.DGiSta_capabilityName{color:var(--dsw-alias-label-primary);font-size:12px;line-height:18px}.DGiSta_capabilityDescription{color:var(--dsw-alias-label-tertiary);margin-top:1px;font-size:11px;line-height:16px}.DGiSta_capabilityReason{color:var(--dsw-alias-state-warn-primary);margin-top:3px;font-size:11px;line-height:16px}.DGiSta_capabilityEmpty{color:var(--dsw-alias-label-tertiary);padding:8px 0;font-size:12px;line-height:18px}.DGiSta_connectorFailed{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-state-error-primary);border-radius:10px;justify-content:space-between;align-items:center;gap:12px;padding:12px 14px;font-size:12px;line-height:18px;display:flex}";
12
12
  const tagId = "@sparkelf/dsh-client-ui-skill-center/SkillCenterPage.module.css";
13
13
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
14
14
  const tag = document.createElement("style");
@@ -23,6 +23,14 @@ window.__ModuleLoader__.load({
23
23
  "bodyLabel": "DGiSta_bodyLabel",
24
24
  "bodyPre": "DGiSta_bodyPre",
25
25
  "bodyStatus": "DGiSta_bodyStatus",
26
+ "capabilityCopy": "DGiSta_capabilityCopy",
27
+ "capabilityDescription": "DGiSta_capabilityDescription",
28
+ "capabilityEmpty": "DGiSta_capabilityEmpty",
29
+ "capabilityList": "DGiSta_capabilityList",
30
+ "capabilityName": "DGiSta_capabilityName",
31
+ "capabilityReason": "DGiSta_capabilityReason",
32
+ "capabilityRow": "DGiSta_capabilityRow",
33
+ "capabilityTitle": "DGiSta_capabilityTitle",
26
34
  "card": "DGiSta_card",
27
35
  "cardActions": "DGiSta_cardActions",
28
36
  "cardBody": "DGiSta_cardBody",
@@ -35,11 +43,31 @@ window.__ModuleLoader__.load({
35
43
  "cardTitle": "DGiSta_cardTitle",
36
44
  "cardTitleRow": "DGiSta_cardTitleRow",
37
45
  "cards": "DGiSta_cards",
46
+ "connectorCard": "DGiSta_connectorCard",
47
+ "connectorDemoNote": "DGiSta_connectorDemoNote",
48
+ "connectorDemoTag": "DGiSta_connectorDemoTag",
49
+ "connectorDescription": "DGiSta_connectorDescription",
50
+ "connectorError": "DGiSta_connectorError",
51
+ "connectorFailed": "DGiSta_connectorFailed",
52
+ "connectorGrid": "DGiSta_connectorGrid",
53
+ "connectorHead": "DGiSta_connectorHead",
54
+ "connectorIcon": "DGiSta_connectorIcon",
55
+ "connectorIdentity": "DGiSta_connectorIdentity",
56
+ "connectorName": "DGiSta_connectorName",
57
+ "connectorTab": "DGiSta_connectorTab",
58
+ "connectorToggleLabel": "DGiSta_connectorToggleLabel",
59
+ "connectorToggleRow": "DGiSta_connectorToggleRow",
60
+ "connectorVendor": "DGiSta_connectorVendor",
38
61
  "detail": "DGiSta_detail",
39
62
  "detailLabel": "DGiSta_detailLabel",
40
63
  "detailRow": "DGiSta_detailRow",
41
64
  "detailValue": "DGiSta_detailValue",
42
65
  "dialog": "DGiSta_dialog",
66
+ "dialogBody": "DGiSta_dialogBody",
67
+ "dialogClose": "DGiSta_dialogClose",
68
+ "dialogFooter": "DGiSta_dialogFooter",
69
+ "dialogHeader": "DGiSta_dialogHeader",
70
+ "dialogTitle": "DGiSta_dialogTitle",
43
71
  "field": "DGiSta_field",
44
72
  "fieldLabel": "DGiSta_fieldLabel",
45
73
  "form": "DGiSta_form",
@@ -53,18 +81,35 @@ window.__ModuleLoader__.load({
53
81
  "markDanger": "DGiSta_markDanger",
54
82
  "markOff": "DGiSta_markOff",
55
83
  "page": "DGiSta_page",
84
+ "pageContent": "DGiSta_pageContent",
56
85
  "pageHead": "DGiSta_pageHead",
57
86
  "pageTitle": "DGiSta_pageTitle",
87
+ "plazaBadge": "DGiSta_plazaBadge",
88
+ "plazaBadgeApproved": "DGiSta_plazaBadgeApproved",
89
+ "plazaBadgeLocal": "DGiSta_plazaBadgeLocal",
90
+ "plazaBadgePending": "DGiSta_plazaBadgePending",
91
+ "plazaBadgeRejected": "DGiSta_plazaBadgeRejected",
92
+ "plazaPanel": "DGiSta_plazaPanel",
93
+ "plazaReason": "DGiSta_plazaReason",
94
+ "plazaScopeHint": "DGiSta_plazaScopeHint",
95
+ "plazaSharedTag": "DGiSta_plazaSharedTag",
58
96
  "progressCount": "DGiSta_progressCount",
59
97
  "progressFill": "DGiSta_progressFill",
60
98
  "progressLabel": "DGiSta_progressLabel",
61
99
  "progressRow": "DGiSta_progressRow",
62
100
  "progressTrack": "DGiSta_progressTrack",
63
- "search": "DGiSta_search",
101
+ "publishDialog": "DGiSta_publishDialog",
102
+ "searchClear": "DGiSta_searchClear",
103
+ "searchField": "DGiSta_searchField",
64
104
  "status": "DGiSta_status",
65
105
  "statusError": "DGiSta_statusError",
66
106
  "switch": "DGiSta_switch",
67
107
  "switchOn": "DGiSta_switchOn",
108
+ "tab": "DGiSta_tab",
109
+ "tabActive": "DGiSta_tabActive",
110
+ "tabCount": "DGiSta_tabCount",
111
+ "tabPanel": "DGiSta_tabPanel",
112
+ "tabs": "DGiSta_tabs",
68
113
  "textarea": "DGiSta_textarea",
69
114
  "toolbar": "DGiSta_toolbar",
70
115
  "workspaceBadge": "DGiSta_workspaceBadge"
@@ -79,25 +124,45 @@ window.__ModuleLoader__.load({
79
124
  */
80
125
  /** Route paths, mirrored from the host (`src/index.ts` ROUTES). */
81
126
  const API = {
82
- list: "/api/dsh-skill-center/list",
83
- setEnabled: "/api/dsh-skill-center/set-enabled",
84
- create: "/api/dsh-skill-center/create",
85
- remove: "/api/dsh-skill-center/delete",
86
- content: "/api/dsh-skill-center/content",
87
- translationProgress: "/api/dsh-skill-center/translation-progress"
127
+ list: "api/dsh-skill-center/list",
128
+ setEnabled: "api/dsh-skill-center/set-enabled",
129
+ create: "api/dsh-skill-center/create",
130
+ remove: "api/dsh-skill-center/delete",
131
+ content: "api/dsh-skill-center/content",
132
+ translationProgress: "api/dsh-skill-center/translation-progress",
133
+ plaza: "integrations/dataops/skill-plaza",
134
+ reviewContext: "integrations/dataops/review-context",
135
+ rbac: "integrations/dataops/rbac"
88
136
  };
137
+ /**
138
+ * Resolve one host route against the document's base URI.
139
+ *
140
+ * The same plugin is served at the origin root (`http://host/` → `/api/...`) and
141
+ * under the DataOps same-origin gateway (`http://host/dsh/` → `/dsh/api/...`).
142
+ * A leading slash would pin every request to the origin root and 404 inside the
143
+ * iframe; a relative path keeps both deployments on the route family the host
144
+ * registered.
145
+ * @param path - route path relative to the document base.
146
+ * @returns absolute URL for fetch.
147
+ */
148
+ const routeUrl = (path) => {
149
+ const base = typeof document === "undefined" ? "http://localhost/" : document.baseURI;
150
+ return new URL(path, base).href;
151
+ };
152
+ /** The sharing bridge could not answer (503): show local/disabled, never fake a status. */
153
+ var PlazaUnavailableError = class extends Error {};
89
154
  /** One thrown API error carrying the host's message. */
90
155
  var ApiError = class extends Error {};
91
156
  /** Skill center API client. */
92
157
  var SkillApi = class {
93
158
  /** Fetch the grouped skill list. */
94
159
  async list(cwd) {
95
- const url = typeof cwd === "string" && cwd.trim() !== "" ? `${API.list}?cwd=${encodeURIComponent(cwd)}` : API.list;
160
+ const url = typeof cwd === "string" && cwd.trim() !== "" ? `${routeUrl(API.list)}?cwd=${encodeURIComponent(cwd)}` : routeUrl(API.list);
96
161
  return this.request(url);
97
162
  }
98
163
  /** Enable or disable a skill by rewriting its frontmatter flag. */
99
164
  async setEnabled(name, path, enabled) {
100
- return this.request(API.setEnabled, {
165
+ return this.request(routeUrl(API.setEnabled), {
101
166
  method: "POST",
102
167
  body: {
103
168
  name,
@@ -108,14 +173,14 @@ window.__ModuleLoader__.load({
108
173
  }
109
174
  /** Create a skill file under the user or project root. */
110
175
  async create(payload) {
111
- return this.request(API.create, {
176
+ return this.request(routeUrl(API.create), {
112
177
  method: "POST",
113
178
  body: payload
114
179
  });
115
180
  }
116
181
  /** Delete a skill by moving it into the recoverable trash. */
117
182
  async remove(name, path) {
118
- return this.request(API.remove, {
183
+ return this.request(routeUrl(API.remove), {
119
184
  method: "POST",
120
185
  body: {
121
186
  name,
@@ -135,14 +200,125 @@ window.__ModuleLoader__.load({
135
200
  const params = new URLSearchParams({ name });
136
201
  if (path !== void 0 && path !== "") params.set("path", path);
137
202
  if (cwd !== void 0 && cwd !== "") params.set("cwd", cwd);
138
- return this.request(API.content + "?" + params.toString());
203
+ return this.request(routeUrl(API.content) + "?" + params.toString());
139
204
  }
140
205
  /**
141
206
  * The translated share of the skill set, or undefined when the host has not
142
207
  * been told where the translations live (the route then answers `{}`).
143
208
  */
144
209
  async translationProgress() {
145
- return (await this.request(API.translationProgress)).progress;
210
+ return (await this.request(routeUrl(API.translationProgress))).progress;
211
+ }
212
+ /** The caller's review role and department scope, from the DataOps bridge. */
213
+ async reviewContext() {
214
+ const response = await fetch(routeUrl(API.reviewContext));
215
+ const body = await this.readBody(response);
216
+ if (response.status === 503) throw new PlazaUnavailableError("review context is not active");
217
+ if (!response.ok) throw new ApiError(this.errorOf(body, response.status));
218
+ const record = typeof body === "object" && body !== null ? body : {};
219
+ const review = typeof record.review === "object" && record.review !== null ? record.review : {};
220
+ return {
221
+ canReview: review.canReview === true || record.canReview === true,
222
+ canReviewGlobal: review.canReviewGlobal === true || record.canReviewGlobal === true,
223
+ departmentCode: typeof record.departmentCode === "string" ? record.departmentCode : null,
224
+ departmentPath: Array.isArray(record.departmentPath) ? record.departmentPath.flatMap((row) => {
225
+ if (typeof row !== "object" || row === null) return [];
226
+ const node = row;
227
+ return typeof node.code === "string" && typeof node.name === "string" ? [{
228
+ code: node.code,
229
+ name: node.name
230
+ }] : [];
231
+ }) : [],
232
+ roleCodes: Array.isArray(record.roleCodes) ? record.roleCodes.filter((code) => typeof code === "string") : [],
233
+ ...typeof record.primaryRole === "string" ? { primaryRole: record.primaryRole } : {}
234
+ };
235
+ }
236
+ /** The department tree, for administrators publishing to any department. */
237
+ async departments() {
238
+ const response = await fetch(routeUrl(API.rbac) + "?section=departments");
239
+ const body = await this.readBody(response);
240
+ if (!response.ok) return [];
241
+ if (typeof body !== "object" || body === null || !Array.isArray(body.items)) return [];
242
+ return body.items.flatMap((row) => {
243
+ if (typeof row !== "object" || row === null) return [];
244
+ const node = row;
245
+ return typeof node.code === "string" && typeof node.name === "string" ? [{
246
+ code: node.code,
247
+ name: node.name,
248
+ parentCode: typeof node.parentCode === "string" ? node.parentCode : null
249
+ }] : [];
250
+ });
251
+ }
252
+ /**
253
+ * The plaza records this workspace holds (`mine=1`). A 503 means the
254
+ * sharing service is not active yet; the panel then renders every local
255
+ * skill as local with 上架 disabled.
256
+ */
257
+ async plazaMine() {
258
+ const response = await fetch(routeUrl(API.plaza) + "?mine=1");
259
+ const body = await this.readBody(response);
260
+ if (response.status === 503) throw new PlazaUnavailableError("skill plaza is not active");
261
+ if (!response.ok) throw new ApiError(this.errorOf(body, response.status));
262
+ return (typeof body === "object" && body !== null && Array.isArray(body.skills) ? body.skills : []).filter((row) => typeof row === "object" && row !== null && typeof row.id === "number" && typeof row.name === "string").filter((row) => row.sharedByMe === true || row.reviewStatus !== void 0);
263
+ }
264
+ /** Publish one local skill. The name is the DataOps identity; no path/level leaves the workspace. */
265
+ async plazaSubmit(payload) {
266
+ const response = await fetch(routeUrl(API.plaza), {
267
+ method: "POST",
268
+ headers: { "content-type": "application/json" },
269
+ body: JSON.stringify({
270
+ action: "submit",
271
+ ...payload
272
+ })
273
+ });
274
+ let body = await this.readBody(response);
275
+ if (response.status === 503) throw new PlazaUnavailableError("skill plaza is not active");
276
+ if (!response.ok && response.status === 400 && this.errorOf(body, response.status).includes("unknown action")) {
277
+ const legacy = await fetch(routeUrl(API.plaza), {
278
+ method: "POST",
279
+ headers: { "content-type": "application/json" },
280
+ body: JSON.stringify({
281
+ action: "share",
282
+ ...payload
283
+ })
284
+ });
285
+ body = await this.readBody(legacy);
286
+ if (legacy.status === 503) throw new PlazaUnavailableError("skill plaza is not active");
287
+ if (!legacy.ok) throw new ApiError(this.errorOf(body, legacy.status));
288
+ } else if (!response.ok) throw new ApiError(this.errorOf(body, response.status));
289
+ const skill = typeof body === "object" && body !== null ? body.skill : void 0;
290
+ if (typeof skill !== "object" || skill === null) throw new ApiError("the sharing service returned no skill");
291
+ const row = skill;
292
+ return {
293
+ id: typeof row.id === "number" ? row.id : 0,
294
+ name: typeof row.name === "string" ? row.name : payload.name,
295
+ reviewStatus: row.reviewStatus ?? "pending",
296
+ ...row.sharedByMe === void 0 ? { sharedByMe: true } : { sharedByMe: row.sharedByMe }
297
+ };
298
+ }
299
+ /** Stop sharing one plaza entry owned by this workspace. */
300
+ async plazaUnshare(id) {
301
+ const response = await fetch(routeUrl(API.plaza), {
302
+ method: "POST",
303
+ headers: { "content-type": "application/json" },
304
+ body: JSON.stringify({
305
+ action: "unshare",
306
+ id
307
+ })
308
+ });
309
+ if (response.status === 503) throw new PlazaUnavailableError("skill plaza is not active");
310
+ if (!response.ok) throw new ApiError(this.errorOf(await this.readBody(response), response.status));
311
+ }
312
+ async readBody(response) {
313
+ try {
314
+ return await response.json();
315
+ } catch {
316
+ return;
317
+ }
318
+ }
319
+ errorOf(body, status) {
320
+ const reported = typeof body === "object" && body !== null && typeof body.error === "string" ? body.error : "";
321
+ return reported === "" ? "HTTP " + String(status) : reported;
146
322
  }
147
323
  async request(path, options = {}) {
148
324
  const init = { method: options.method ?? "GET" };
@@ -165,6 +341,563 @@ window.__ModuleLoader__.load({
165
341
  }
166
342
  };
167
343
  //#endregion
344
+ //#region src/client/plaza.ts
345
+ /** Map one local skill name to its share state. */
346
+ function shareOf(name, records) {
347
+ const record = records.get(name);
348
+ if (record === void 0) return {
349
+ status: "local",
350
+ sharedByMe: false
351
+ };
352
+ return {
353
+ status: record.reviewStatus ?? (record.sharedByMe === true ? "approved" : "local"),
354
+ record,
355
+ sharedByMe: record.sharedByMe === true
356
+ };
357
+ }
358
+ /** Whether a share state offers the 上架 / 重新提交 action. */
359
+ function canSubmit(status) {
360
+ return status === "local" || status === "rejected";
361
+ }
362
+ //#endregion
363
+ //#region src/client/connectors.ts
364
+ /**
365
+ * Connector catalogue for the skill center's fourth tab.
366
+ *
367
+ * A connector is a client-side description of one external system the profile
368
+ * can talk to: whether it is enabled, and which capabilities that account may
369
+ * use. The backend owns the authoritative list; this module only parses it and
370
+ * keeps a demo catalogue for profiles whose bridge has not shipped the route
371
+ * yet. Capability rows the account may not use are absent from the answer, so
372
+ * the UI never renders a disabled placeholder for a permission it lacks.
373
+ *
374
+ * @module @sparkelf/dsh-client-ui-skill-center/client/connectors
375
+ */
376
+ /** Same-origin route the host/DataOps bridge may serve the catalogue from. */
377
+ const CONNECTORS_ROUTE = "/api/dsh-skill-center/connectors";
378
+ /** The bridge does not serve the connector route (404/405/501/503). */
379
+ var ConnectorUnavailableError = class extends Error {};
380
+ /** The bridge answered but the request failed for another reason. */
381
+ var ConnectorRequestError = class extends Error {};
382
+ /** Same-origin HTTP source for a backend that supplies the catalogue. */
383
+ var HttpConnectorSource = class {
384
+ route;
385
+ /**
386
+ * @param route - same-origin connector route; overridable for tests.
387
+ */
388
+ constructor(route = CONNECTORS_ROUTE) {
389
+ this.route = route;
390
+ }
391
+ /** Read the catalogue. */
392
+ async list() {
393
+ return this.read(await this.request(this.route));
394
+ }
395
+ /** Enable or disable one connector. */
396
+ async setEnabled(connectorId, enabled) {
397
+ return this.read(await this.request(this.route, {
398
+ connectorId,
399
+ enabled
400
+ }));
401
+ }
402
+ /** Toggle one capability. */
403
+ async setCapability(connectorId, capabilityId, enabled) {
404
+ return this.read(await this.request(this.route, {
405
+ connectorId,
406
+ capabilityId,
407
+ enabled
408
+ }));
409
+ }
410
+ async request(route, body) {
411
+ const init = body === void 0 ? { headers: { accept: "application/json" } } : {
412
+ method: "POST",
413
+ headers: {
414
+ accept: "application/json",
415
+ "content-type": "application/json"
416
+ },
417
+ body: JSON.stringify(body)
418
+ };
419
+ const response = await fetch(route, init);
420
+ if (response.status === 404 || response.status === 405 || response.status === 501 || response.status === 503) throw new ConnectorUnavailableError("connector catalogue is not served");
421
+ if (!response.ok) {
422
+ let detail = "";
423
+ try {
424
+ const payload = await response.json();
425
+ detail = typeof payload.error === "string" ? payload.error : "";
426
+ } catch {}
427
+ throw new ConnectorRequestError(detail === "" ? "HTTP " + String(response.status) : detail);
428
+ }
429
+ try {
430
+ return await response.json();
431
+ } catch {
432
+ throw new ConnectorUnavailableError("connector catalogue is not JSON");
433
+ }
434
+ }
435
+ read(value) {
436
+ return parseConnectorList(value);
437
+ }
438
+ };
439
+ /** Narrow one wire value to a connector capability. */
440
+ function parseCapability(value) {
441
+ if (typeof value !== "object" || value === null) return null;
442
+ const row = value;
443
+ if (typeof row.id !== "string" || row.id === "") return null;
444
+ return {
445
+ id: row.id,
446
+ name: typeof row.name === "string" && row.name !== "" ? row.name : row.id,
447
+ ...typeof row.description === "string" ? { description: row.description } : {},
448
+ enabled: row.enabled === true,
449
+ permitted: row.permitted !== false,
450
+ ...typeof row.unavailableReason === "string" ? { unavailableReason: row.unavailableReason } : {}
451
+ };
452
+ }
453
+ /** Narrow one wire value to a connector. */
454
+ function parseConnector(value) {
455
+ if (typeof value !== "object" || value === null) return null;
456
+ const row = value;
457
+ if (typeof row.id !== "string" || row.id === "" || typeof row.name !== "string" || row.name === "") return null;
458
+ const capabilities = Array.isArray(row.capabilities) ? row.capabilities.flatMap((entry) => parseCapability(entry) ?? []) : [];
459
+ return {
460
+ id: row.id,
461
+ name: row.name,
462
+ ...typeof row.vendor === "string" ? { vendor: row.vendor } : {},
463
+ ...typeof row.description === "string" ? { description: row.description } : {},
464
+ enabled: row.enabled === true,
465
+ ...typeof row.connected === "boolean" ? { connected: row.connected } : {},
466
+ ...typeof row.error === "string" ? { error: row.error } : {},
467
+ capabilities
468
+ };
469
+ }
470
+ /**
471
+ * Parse a catalogue answer. Both a bare array and `{ connectors: [...] }` are
472
+ * accepted, because a bridge may grow the wrapper for counts without breaking
473
+ * the older shape.
474
+ * @param value - decoded JSON body.
475
+ * @returns the connectors the body carries; empty when it carries none.
476
+ */
477
+ function parseConnectorList(value) {
478
+ if (Array.isArray(value)) return value.flatMap((entry) => parseConnector(entry) ?? []);
479
+ if (typeof value !== "object" || value === null) return [];
480
+ const rows = value.connectors;
481
+ return Array.isArray(rows) ? rows.flatMap((entry) => parseConnector(entry) ?? []) : [];
482
+ }
483
+ /** Capabilities this account may see; a `permitted: false` row never renders. */
484
+ function visibleCapabilities(connector) {
485
+ return connector.capabilities.filter((capability) => capability.permitted);
486
+ }
487
+ /**
488
+ * Derive the card state from the catalogue row.
489
+ * @param connector - one catalogue row.
490
+ * @returns `disabled`, `connected`, or `error`.
491
+ */
492
+ function connectorState(connector) {
493
+ if (!connector.enabled) return "disabled";
494
+ return connector.connected === false ? "error" : "connected";
495
+ }
496
+ /**
497
+ * The demo catalogue used when no bridge serves the route.
498
+ *
499
+ * It describes the connector this profile ships and one generic third-party
500
+ * connector, so the tab still demonstrates enable/disable, per-capability
501
+ * switches, a hidden no-permission capability, and an unavailable reason.
502
+ * @returns a fresh mutable copy on every call.
503
+ */
504
+ function demoConnectors() {
505
+ return [{
506
+ id: "wanxiang-ai",
507
+ name: "万相AI中台连接器",
508
+ vendor: "DataOps",
509
+ description: "接收万相AI中台的审批任务,并把处理结果回写中台。",
510
+ enabled: false,
511
+ connected: false,
512
+ capabilities: [
513
+ {
514
+ id: "approval.read",
515
+ name: "读取审批任务",
516
+ description: "拉取当前账号可办理的审批任务",
517
+ enabled: true,
518
+ permitted: true
519
+ },
520
+ {
521
+ id: "approval.handle",
522
+ name: "打开办理",
523
+ description: "跳转到万相AI中台审批详情完成办理",
524
+ enabled: true,
525
+ permitted: true
526
+ },
527
+ {
528
+ id: "task.writeback",
529
+ name: "回写任务状态",
530
+ description: "把办理结果回写到万相AI中台",
531
+ enabled: false,
532
+ permitted: true
533
+ },
534
+ {
535
+ id: "approval.batch",
536
+ name: "批量审批",
537
+ description: "一次处理多条审批任务",
538
+ enabled: false,
539
+ permitted: true,
540
+ unavailableReason: "当前连接未开通批量接口"
541
+ },
542
+ {
543
+ id: "credential.manage",
544
+ name: "管理连接凭据",
545
+ description: "配置或轮换连接凭据",
546
+ enabled: false,
547
+ permitted: false
548
+ }
549
+ ]
550
+ }, {
551
+ id: "work-order",
552
+ name: "通用工单连接器",
553
+ vendor: "第三方系统",
554
+ description: "把外部工单系统的待办接入任务中心。",
555
+ enabled: false,
556
+ connected: false,
557
+ capabilities: [
558
+ {
559
+ id: "ticket.pull",
560
+ name: "拉取工单",
561
+ description: "按账号权限拉取待办工单",
562
+ enabled: true,
563
+ permitted: true
564
+ },
565
+ {
566
+ id: "ticket.comment",
567
+ name: "回写处理意见",
568
+ description: "把处理意见回写到工单系统",
569
+ enabled: false,
570
+ permitted: true
571
+ },
572
+ {
573
+ id: "ticket.admin",
574
+ name: "工单配置管理",
575
+ description: "维护工单字段与流转规则",
576
+ enabled: false,
577
+ permitted: false
578
+ }
579
+ ]
580
+ }];
581
+ }
582
+ /**
583
+ * Read the catalogue, falling back to the demo rows when the bridge has no
584
+ * route. Any other failure propagates: a broken bridge is not "no connectors".
585
+ * @param source - the deployed source.
586
+ * @param demo - demo factory (tests pass a fixed list).
587
+ * @returns the catalogue and whether it is the demo fallback.
588
+ */
589
+ async function readConnectorCatalogue(source, demo = demoConnectors) {
590
+ try {
591
+ return {
592
+ connectors: await source.list(),
593
+ demo: false
594
+ };
595
+ } catch (error) {
596
+ if (error instanceof ConnectorUnavailableError) return {
597
+ connectors: demo(),
598
+ demo: true
599
+ };
600
+ throw error;
601
+ }
602
+ }
603
+ //#endregion
604
+ //#region src/client/ConnectorsTab.tsx
605
+ /** Status label and tone for one connector. */
606
+ function statusOf(connector, t) {
607
+ const state = connectorState(connector);
608
+ if (state === "error") return {
609
+ label: t("connector.error"),
610
+ tone: "danger"
611
+ };
612
+ if (state === "connected") return {
613
+ label: t("connector.connected"),
614
+ tone: "success"
615
+ };
616
+ return {
617
+ label: t("connector.disabled"),
618
+ tone: "neutral"
619
+ };
620
+ }
621
+ /** Whether the query matches a connector or one of its visible capabilities. */
622
+ function matchesQuery(connector, needle) {
623
+ if (needle === "") return true;
624
+ return [
625
+ connector.name,
626
+ connector.vendor ?? "",
627
+ connector.description ?? "",
628
+ ...visibleCapabilities(connector).flatMap((capability) => [capability.name, capability.description ?? ""])
629
+ ].some((value) => value.toLowerCase().includes(needle));
630
+ }
631
+ /**
632
+ * Render one connector card.
633
+ * @param props.connector - the catalogue row.
634
+ * @param props.busy - whether a write for this connector is in flight.
635
+ * @param props.t - dictionary resolver.
636
+ * @param props.onToggleConnector - enable/disable request.
637
+ * @param props.onToggleCapability - capability toggle request.
638
+ * @returns the card.
639
+ */
640
+ function ConnectorCard({ connector, busy, t, onToggleConnector, onToggleCapability }) {
641
+ const status = statusOf(connector, t);
642
+ const capabilities = visibleCapabilities(connector);
643
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
644
+ className: SkillCenterPage_module_css_default.connectorCard,
645
+ "data-connector-id": connector.id,
646
+ "data-connector-enabled": connector.enabled,
647
+ children: [
648
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
649
+ className: SkillCenterPage_module_css_default.connectorHead,
650
+ children: [
651
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
652
+ className: SkillCenterPage_module_css_default.connectorIcon,
653
+ "aria-hidden": "true",
654
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLinkOutline16, { size: 16 })
655
+ }),
656
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
657
+ className: SkillCenterPage_module_css_default.connectorIdentity,
658
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
659
+ className: SkillCenterPage_module_css_default.connectorName,
660
+ children: connector.name
661
+ }), connector.vendor === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
662
+ className: SkillCenterPage_module_css_default.connectorVendor,
663
+ children: connector.vendor
664
+ })]
665
+ }),
666
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
667
+ tone: status.tone,
668
+ children: status.label
669
+ })
670
+ ]
671
+ }),
672
+ connector.description === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
673
+ className: SkillCenterPage_module_css_default.connectorDescription,
674
+ children: connector.description
675
+ }),
676
+ connector.enabled && connector.error !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
677
+ className: SkillCenterPage_module_css_default.connectorError,
678
+ role: "status",
679
+ children: connector.error
680
+ }) : null,
681
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
682
+ className: SkillCenterPage_module_css_default.connectorToggleRow,
683
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
684
+ className: SkillCenterPage_module_css_default.connectorToggleLabel,
685
+ children: connector.enabled ? t("connector.enabled") : t("connector.disabled")
686
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
687
+ checked: connector.enabled,
688
+ disabled: busy,
689
+ label: (connector.enabled ? t("connector.disable") : t("connector.enable")) + " " + connector.name,
690
+ onChange: (next) => {
691
+ onToggleConnector(connector, next);
692
+ }
693
+ })]
694
+ }),
695
+ connector.enabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
696
+ className: SkillCenterPage_module_css_default.capabilityList,
697
+ "data-connector-capabilities": true,
698
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
699
+ className: SkillCenterPage_module_css_default.capabilityTitle,
700
+ children: t("connector.capabilities")
701
+ }), capabilities.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
702
+ className: SkillCenterPage_module_css_default.capabilityEmpty,
703
+ children: t("connector.noCapabilities")
704
+ }) : capabilities.map((capability) => {
705
+ const unavailable = capability.unavailableReason !== void 0;
706
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
707
+ className: SkillCenterPage_module_css_default.capabilityRow,
708
+ "data-capability-id": capability.id,
709
+ "data-capability-enabled": capability.enabled,
710
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
711
+ className: SkillCenterPage_module_css_default.capabilityCopy,
712
+ children: [
713
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
714
+ className: SkillCenterPage_module_css_default.capabilityName,
715
+ children: capability.name
716
+ }),
717
+ capability.description === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
718
+ className: SkillCenterPage_module_css_default.capabilityDescription,
719
+ children: capability.description
720
+ }),
721
+ capability.unavailableReason === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
722
+ className: SkillCenterPage_module_css_default.capabilityReason,
723
+ children: [
724
+ t("connector.unavailable"),
725
+ " · ",
726
+ capability.unavailableReason
727
+ ]
728
+ })
729
+ ]
730
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
731
+ checked: capability.enabled,
732
+ disabled: busy || unavailable,
733
+ label: (capability.enabled ? t("connector.disable") : t("connector.enable")) + " " + capability.name,
734
+ onChange: (next) => {
735
+ onToggleCapability(connector, capability, next);
736
+ }
737
+ })]
738
+ }, capability.id);
739
+ })]
740
+ }) : null
741
+ ]
742
+ });
743
+ }
744
+ /**
745
+ * Render the connector tab body.
746
+ * @param props - catalogue state, search text, and the two write handlers.
747
+ * @returns the connector cards, or the loading/failure/empty status.
748
+ */
749
+ function ConnectorsTab(props) {
750
+ const { state, query, busyId, t, onRetry, onToggleConnector, onToggleCapability } = props;
751
+ if (state.kind === "loading") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
752
+ className: SkillCenterPage_module_css_default.status,
753
+ children: t("connector.loading")
754
+ });
755
+ if (state.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
756
+ className: SkillCenterPage_module_css_default.connectorFailed,
757
+ role: "alert",
758
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
759
+ t("connector.failed"),
760
+ ":",
761
+ state.message
762
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
763
+ variant: "outline",
764
+ size: "sm",
765
+ onClick: onRetry,
766
+ children: t("connector.retry")
767
+ })]
768
+ });
769
+ const needle = query.trim().toLowerCase();
770
+ const connectors = state.catalogue.connectors.filter((connector) => matchesQuery(connector, needle));
771
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
772
+ className: SkillCenterPage_module_css_default.connectorTab,
773
+ "data-connector-catalogue": true,
774
+ "data-demo": state.catalogue.demo,
775
+ children: [state.catalogue.demo ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
776
+ className: SkillCenterPage_module_css_default.connectorDemoNote,
777
+ role: "status",
778
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
779
+ className: SkillCenterPage_module_css_default.connectorDemoTag,
780
+ children: t("connector.demoTag")
781
+ }), t("connector.demo")]
782
+ }) : null, connectors.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
783
+ className: SkillCenterPage_module_css_default.status,
784
+ children: state.catalogue.connectors.length === 0 ? t("connector.empty") : t("connector.noMatches")
785
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
786
+ className: SkillCenterPage_module_css_default.connectorGrid,
787
+ children: connectors.map((connector) => {
788
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConnectorCard, {
789
+ connector,
790
+ busy: busyId === connector.id || busyId?.startsWith(connector.id + ":") === true,
791
+ t,
792
+ onToggleConnector,
793
+ onToggleCapability
794
+ }, connector.id);
795
+ })
796
+ })]
797
+ });
798
+ }
799
+ //#endregion
800
+ //#region src/client/scope.ts
801
+ /** Read the identity the dataops-account plugin publishes. */
802
+ function readAccountIdentity() {
803
+ if (typeof window === "undefined") return void 0;
804
+ const fromWindow = window.__DATAOPS_USER__;
805
+ if (fromWindow !== void 0) return fromWindow;
806
+ if (typeof document === "undefined") return void 0;
807
+ const dataset = document.documentElement.dataset;
808
+ if (dataset.dataopsAccountId === void 0 && dataset.dataopsAccountName === void 0) return void 0;
809
+ const identity = {};
810
+ if (dataset.dataopsAccountId !== void 0) identity.id = dataset.dataopsAccountId;
811
+ if (dataset.dataopsAccountName !== void 0) identity.displayName = dataset.dataopsAccountName;
812
+ return identity;
813
+ }
814
+ /** Classify the caller: global review means super admin/admin; review means department admin. */
815
+ function scopeRole(scope) {
816
+ if (scope?.canReviewGlobal === true) return "admin";
817
+ if (scope?.canReview === true) return "dept-admin";
818
+ return "user";
819
+ }
820
+ /** Visibilities this caller may select. */
821
+ function allowedVisibilities(scope) {
822
+ if (scopeRole(scope) === "admin") return [
823
+ "global",
824
+ "department",
825
+ "private"
826
+ ];
827
+ if (hasDepartment(scope)) return ["department", "private"];
828
+ return ["private"];
829
+ }
830
+ /** Whether the caller belongs to a department (needed for department visibility). */
831
+ function hasDepartment(scope) {
832
+ return typeof scope?.departmentCode === "string" && scope.departmentCode !== "";
833
+ }
834
+ /** First-run default: admins publish globally, everyone else to their department, else private. */
835
+ function defaultVisibility(scope) {
836
+ if (scopeRole(scope) === "admin") return "global";
837
+ return hasDepartment(scope) ? "department" : "private";
838
+ }
839
+ /** The caller's own department code. */
840
+ function ownDepartment(scope) {
841
+ const code = scope?.departmentCode;
842
+ return typeof code === "string" && code !== "" ? code : void 0;
843
+ }
844
+ /**
845
+ * Coerce a remembered choice into one this caller may still make.
846
+ *
847
+ * A saved global choice is dropped for a non-admin; a saved department code is
848
+ * kept only when it is the caller's own department (department admins/users)
849
+ * or still present in the admin's fetched department list.
850
+ */
851
+ function sanitizeChoice(saved, scope, departments = []) {
852
+ const allowed = allowedVisibilities(scope);
853
+ const visibility = saved !== void 0 && allowed.includes(saved.visibility) ? saved.visibility : defaultVisibility(scope);
854
+ if (visibility !== "department") return { visibility };
855
+ if (scopeRole(scope) === "admin") {
856
+ const savedCode = saved?.departmentCode;
857
+ if (savedCode !== void 0 && departments.some((department) => department.code === savedCode)) return {
858
+ visibility,
859
+ departmentCode: savedCode
860
+ };
861
+ const code = ownDepartment(scope) ?? departments[0]?.code;
862
+ return code === void 0 ? { visibility } : {
863
+ visibility,
864
+ departmentCode: code
865
+ };
866
+ }
867
+ const code = ownDepartment(scope);
868
+ return code === void 0 ? { visibility } : {
869
+ visibility,
870
+ departmentCode: code
871
+ };
872
+ }
873
+ /** localStorage key, per DataOps user. */
874
+ function scopeStorageKey(identity) {
875
+ return "dsh-skill-center:plaza-scope:" + (identity?.id ?? identity?.username ?? "anonymous");
876
+ }
877
+ /** Read a remembered choice (invalid JSON is treated as no choice). */
878
+ function readSavedScope(storage, key) {
879
+ try {
880
+ const raw = storage.getItem(key);
881
+ if (raw === null || raw === "") return void 0;
882
+ const parsed = JSON.parse(raw);
883
+ if (typeof parsed !== "object" || parsed === null) return void 0;
884
+ const value = parsed;
885
+ if (value.visibility !== "global" && value.visibility !== "department" && value.visibility !== "private") return void 0;
886
+ return {
887
+ visibility: value.visibility,
888
+ ...typeof value.departmentCode === "string" && value.departmentCode !== "" ? { departmentCode: value.departmentCode } : {}
889
+ };
890
+ } catch {
891
+ return;
892
+ }
893
+ }
894
+ /** Persist one choice. */
895
+ function writeSavedScope(storage, key, choice) {
896
+ try {
897
+ storage.setItem(key, JSON.stringify(choice));
898
+ } catch {}
899
+ }
900
+ //#endregion
168
901
  //#region src/client/SkillCenterPage.tsx
169
902
  /**
170
903
  * Skill center page. Browses the loaded skills grouped by source, toggles model
@@ -175,6 +908,8 @@ window.__ModuleLoader__.load({
175
908
  *
176
909
  * @module @sparkelf/dsh-client-ui-skill-center/client/SkillCenterPage
177
910
  */
911
+ /** Group key the host uses for skills that ship inside the runtime. */
912
+ const BUNDLED_GROUP = "bundled";
178
913
  /**
179
914
  * One labelled create-form field.
180
915
  * @param props - the field's label and the control it wraps.
@@ -195,7 +930,7 @@ window.__ModuleLoader__.load({
195
930
  * with, its toggle, and its delete action.
196
931
  * @returns the row.
197
932
  */
198
- function SkillCard({ skill, api, cwd, t, onToggle, onDelete }) {
933
+ function SkillCard({ skill, api, cwd, t, share, shareBusy, shareDisabled, onToggle, onDelete, onShare, onUnshare }) {
199
934
  const [open, setOpen] = (0, react.useState)(false);
200
935
  const [body, setBody] = (0, react.useState)({ kind: "loading" });
201
936
  (0, react.useEffect)(() => {
@@ -224,6 +959,7 @@ window.__ModuleLoader__.load({
224
959
  cwd
225
960
  ]);
226
961
  const foreign = skill.isActiveWorkspace === false && skill.workspaceName !== void 0;
962
+ const shareLabel = share.status === "approved" ? t("plaza.statusApproved") : share.status === "pending" ? t("plaza.statusPending") : share.status === "rejected" ? t("plaza.statusRejected") : t("plaza.statusLocal");
227
963
  const details = [];
228
964
  if (skill.whenToUse !== void 0) details.push({
229
965
  key: "detail.whenToUse",
@@ -243,6 +979,8 @@ window.__ModuleLoader__.load({
243
979
  });
244
980
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
245
981
  className: foreign ? SkillCenterPage_module_css_default.card + " " + SkillCenterPage_module_css_default.cardForeign : SkillCenterPage_module_css_default.card,
982
+ "data-skill-name": skill.name,
983
+ "data-plaza-status": share.status,
246
984
  children: [
247
985
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
248
986
  className: SkillCenterPage_module_css_default.cardHead,
@@ -251,38 +989,62 @@ window.__ModuleLoader__.load({
251
989
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSkillOutlineRegular, { size: 16 })
252
990
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
253
991
  className: SkillCenterPage_module_css_default.cardTitleRow,
254
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
255
- className: SkillCenterPage_module_css_default.cardTitle,
256
- children: skill.i18n?.title ?? skill.name
257
- }), skill.workspaceName === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
258
- className: SkillCenterPage_module_css_default.workspaceBadge,
259
- children: skill.workspaceName
260
- })]
261
- })]
262
- }),
263
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
264
- className: SkillCenterPage_module_css_default.cardBody,
265
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
266
- className: SkillCenterPage_module_css_default.cardSummary,
267
- children: skill.i18n?.summary ?? skill.description
268
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
269
- className: SkillCenterPage_module_css_default.cardMarks,
270
992
  children: [
271
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
272
- className: skill.modelInvocable ? SkillCenterPage_module_css_default.mark + " " + SkillCenterPage_module_css_default.markOn : SkillCenterPage_module_css_default.mark + " " + SkillCenterPage_module_css_default.markOff,
273
- children: t("skill.modelInvocable")
993
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
994
+ className: SkillCenterPage_module_css_default.cardTitle,
995
+ children: skill.i18n?.title ?? skill.name
996
+ }),
997
+ skill.workspaceName === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
998
+ className: SkillCenterPage_module_css_default.workspaceBadge,
999
+ children: skill.workspaceName
274
1000
  }),
275
1001
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
276
- className: skill.userInvocable ? SkillCenterPage_module_css_default.mark + " " + SkillCenterPage_module_css_default.markOn : SkillCenterPage_module_css_default.mark + " " + SkillCenterPage_module_css_default.markOff,
277
- children: t("skill.userInvocable")
1002
+ className: SkillCenterPage_module_css_default.plazaBadge + " " + (share.status === "approved" ? SkillCenterPage_module_css_default.plazaBadgeApproved : share.status === "rejected" ? SkillCenterPage_module_css_default.plazaBadgeRejected : share.status === "pending" ? SkillCenterPage_module_css_default.plazaBadgePending : SkillCenterPage_module_css_default.plazaBadgeLocal),
1003
+ "data-plaza-status": share.status,
1004
+ children: shareLabel
278
1005
  }),
279
- skill.linked === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
280
- className: SkillCenterPage_module_css_default.mark + " " + SkillCenterPage_module_css_default.markDanger,
281
- children: t("skill.linked")
1006
+ share.status === "approved" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1007
+ className: SkillCenterPage_module_css_default.plazaSharedTag,
1008
+ "data-plaza-shared": true,
1009
+ children: t("plaza.sharedTag")
282
1010
  }) : null
283
1011
  ]
284
1012
  })]
285
1013
  }),
1014
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1015
+ className: SkillCenterPage_module_css_default.cardBody,
1016
+ children: [
1017
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1018
+ className: SkillCenterPage_module_css_default.cardSummary,
1019
+ children: skill.i18n?.summary ?? skill.description
1020
+ }),
1021
+ share.status === "rejected" && share.record?.reviewNote !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1022
+ className: SkillCenterPage_module_css_default.plazaReason,
1023
+ children: [
1024
+ t("plaza.reason"),
1025
+ ": ",
1026
+ share.record.reviewNote
1027
+ ]
1028
+ }) : null,
1029
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1030
+ className: SkillCenterPage_module_css_default.cardMarks,
1031
+ children: [
1032
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1033
+ className: skill.modelInvocable ? SkillCenterPage_module_css_default.mark + " " + SkillCenterPage_module_css_default.markOn : SkillCenterPage_module_css_default.mark + " " + SkillCenterPage_module_css_default.markOff,
1034
+ children: t("skill.modelInvocable")
1035
+ }),
1036
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1037
+ className: skill.userInvocable ? SkillCenterPage_module_css_default.mark + " " + SkillCenterPage_module_css_default.markOn : SkillCenterPage_module_css_default.mark + " " + SkillCenterPage_module_css_default.markOff,
1038
+ children: t("skill.userInvocable")
1039
+ }),
1040
+ skill.linked === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1041
+ className: SkillCenterPage_module_css_default.mark + " " + SkillCenterPage_module_css_default.markDanger,
1042
+ children: t("skill.linked")
1043
+ }) : null
1044
+ ]
1045
+ })
1046
+ ]
1047
+ }),
286
1048
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
287
1049
  className: SkillCenterPage_module_css_default.cardEnd,
288
1050
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
@@ -295,21 +1057,42 @@ window.__ModuleLoader__.load({
295
1057
  }
296
1058
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
297
1059
  className: SkillCenterPage_module_css_default.cardActions,
298
- children: [skill.path === void 0 || skill.linked === true ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
299
- variant: "outline",
300
- size: "sm",
301
- onClick: () => {
302
- onDelete(skill);
303
- },
304
- children: t("action.delete")
305
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
306
- variant: "outline",
307
- size: "sm",
308
- onClick: () => {
309
- setOpen(true);
310
- },
311
- children: t("action.showDetail")
312
- })]
1060
+ children: [
1061
+ canSubmit(share.status) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1062
+ variant: "primary",
1063
+ size: "sm",
1064
+ disabled: shareBusy || shareDisabled,
1065
+ onClick: () => {
1066
+ onShare(skill);
1067
+ },
1068
+ children: share.status === "rejected" ? t("plaza.resubmit") : t("plaza.share")
1069
+ }) : null,
1070
+ share.sharedByMe && share.record !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1071
+ variant: "outline",
1072
+ size: "sm",
1073
+ disabled: shareBusy,
1074
+ onClick: () => {
1075
+ if (share.record !== void 0) onUnshare(skill, share.record.id);
1076
+ },
1077
+ children: t("plaza.unshare")
1078
+ }) : null,
1079
+ skill.path === void 0 || skill.linked === true ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1080
+ variant: "outline",
1081
+ size: "sm",
1082
+ onClick: () => {
1083
+ onDelete(skill);
1084
+ },
1085
+ children: t("action.delete")
1086
+ }),
1087
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1088
+ variant: "outline",
1089
+ size: "sm",
1090
+ onClick: () => {
1091
+ setOpen(true);
1092
+ },
1093
+ children: t("action.showDetail")
1094
+ })
1095
+ ]
313
1096
  })]
314
1097
  }),
315
1098
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
@@ -376,8 +1159,13 @@ window.__ModuleLoader__.load({
376
1159
  */
377
1160
  function SkillCenterPage({ t, renderSlot, ...runtime }) {
378
1161
  const api = (0, react.useMemo)(() => new SkillApi(), []);
1162
+ const connectorSource = (0, react.useMemo)(() => new HttpConnectorSource(), []);
379
1163
  const [state, setState] = (0, react.useState)({ kind: "loading" });
1164
+ const [tab, setTab] = (0, react.useState)("builtin");
380
1165
  const [query, setQuery] = (0, react.useState)("");
1166
+ const [connectors, setConnectors] = (0, react.useState)({ kind: "loading" });
1167
+ const [connectorBusyId, setConnectorBusyId] = (0, react.useState)(null);
1168
+ const [connectorNotice, setConnectorNotice] = (0, react.useState)(null);
381
1169
  const [progress, setProgress] = (0, react.useState)(void 0);
382
1170
  const [creating, setCreating] = (0, react.useState)(false);
383
1171
  const [draft, setDraft] = (0, react.useState)({
@@ -387,6 +1175,17 @@ window.__ModuleLoader__.load({
387
1175
  content: "",
388
1176
  root: "user"
389
1177
  });
1178
+ const [plaza, setPlaza] = (0, react.useState)({ kind: "loading" });
1179
+ const [shareTarget, setShareTarget] = (0, react.useState)(null);
1180
+ const [shareInstruction, setShareInstruction] = (0, react.useState)("");
1181
+ const [shareTags, setShareTags] = (0, react.useState)("");
1182
+ const [shareLoading, setShareLoading] = (0, react.useState)(false);
1183
+ const [shareBusy, setShareBusy] = (0, react.useState)(false);
1184
+ const [shareError, setShareError] = (0, react.useState)(null);
1185
+ const [reviewScope, setReviewScope] = (0, react.useState)(void 0);
1186
+ const [departments, setDepartments] = (0, react.useState)([]);
1187
+ const [shareVisibility, setShareVisibility] = (0, react.useState)("private");
1188
+ const [shareDepartment, setShareDepartment] = (0, react.useState)(void 0);
390
1189
  const useWorkspaces = runtime.useWorkspaces;
391
1190
  const workspaces = useWorkspaces === void 0 ? [] : useWorkspaces((snapshot) => snapshot.items);
392
1191
  const scope = (0, react.useMemo)(() => {
@@ -405,9 +1204,59 @@ window.__ModuleLoader__.load({
405
1204
  });
406
1205
  }
407
1206
  }, [api, scope]);
1207
+ const loadPlaza = (0, react.useCallback)(async () => {
1208
+ try {
1209
+ const rows = await api.plazaMine();
1210
+ setPlaza({
1211
+ kind: "ready",
1212
+ records: new Map(rows.map((row) => [row.name, row]))
1213
+ });
1214
+ } catch (error) {
1215
+ if (error instanceof PlazaUnavailableError) setPlaza({ kind: "unavailable" });
1216
+ else setPlaza({
1217
+ kind: "failed",
1218
+ message: error instanceof Error ? error.message : String(error)
1219
+ });
1220
+ }
1221
+ }, [api]);
408
1222
  (0, react.useEffect)(() => {
409
1223
  load();
410
1224
  }, [load]);
1225
+ (0, react.useEffect)(() => {
1226
+ loadPlaza();
1227
+ }, [loadPlaza]);
1228
+ const loadConnectors = (0, react.useCallback)(async () => {
1229
+ setConnectors({ kind: "loading" });
1230
+ setConnectorNotice(null);
1231
+ try {
1232
+ setConnectors({
1233
+ kind: "ready",
1234
+ catalogue: await readConnectorCatalogue(connectorSource)
1235
+ });
1236
+ } catch (error) {
1237
+ setConnectors({
1238
+ kind: "failed",
1239
+ message: error instanceof Error ? error.message : String(error)
1240
+ });
1241
+ }
1242
+ }, [connectorSource]);
1243
+ (0, react.useEffect)(() => {
1244
+ loadConnectors();
1245
+ }, [loadConnectors]);
1246
+ (0, react.useEffect)(() => {
1247
+ let cancelled = false;
1248
+ api.reviewContext().then(async (scope) => {
1249
+ if (cancelled) return;
1250
+ setReviewScope(scope);
1251
+ if (scope.canReviewGlobal === true) {
1252
+ const rows = await api.departments();
1253
+ if (!cancelled) setDepartments(rows);
1254
+ }
1255
+ }).catch(() => {});
1256
+ return () => {
1257
+ cancelled = true;
1258
+ };
1259
+ }, [api]);
411
1260
  (0, react.useEffect)(() => {
412
1261
  let cancelled = false;
413
1262
  api.translationProgress().then((p) => {
@@ -417,6 +1266,15 @@ window.__ModuleLoader__.load({
417
1266
  cancelled = true;
418
1267
  };
419
1268
  }, [api]);
1269
+ const plazaRecords = plaza.kind === "ready" ? plaza.records : /* @__PURE__ */ new Map();
1270
+ const visibilityOptions = allowedVisibilities(reviewScope);
1271
+ const role = scopeRole(reviewScope);
1272
+ const ownCode = ownDepartment(reviewScope);
1273
+ const departmentChoices = role === "admin" && departments.length > 0 ? departments : (reviewScope?.departmentPath ?? []).filter((node) => node.code !== "");
1274
+ const selectableDepartments = role === "admin" ? departmentChoices : ownCode === void 0 ? [] : [{
1275
+ code: ownCode,
1276
+ name: departmentChoices.find((node) => node.code === ownCode)?.name ?? ownCode
1277
+ }];
420
1278
  const groups = (0, react.useMemo)(() => {
421
1279
  if (state.kind !== "ready") return [];
422
1280
  const q = query.trim().toLowerCase();
@@ -426,6 +1284,32 @@ window.__ModuleLoader__.load({
426
1284
  skills: g.skills.filter((s) => s.name.toLowerCase().includes(q) || s.description.toLowerCase().includes(q) || (s.i18n?.title ?? "").toLowerCase().includes(q) || (s.i18n?.description ?? "").toLowerCase().includes(q) || (s.i18n?.summary ?? "").toLowerCase().includes(q) || (s.whenToUse ?? "").toLowerCase().includes(q))
427
1285
  })).filter((g) => g.skills.length > 0);
428
1286
  }, [state, query]);
1287
+ const builtinGroups = (0, react.useMemo)(() => groups.filter((group) => group.key === BUNDLED_GROUP), [groups]);
1288
+ const personalGroups = (0, react.useMemo)(() => groups.filter((group) => group.key !== BUNDLED_GROUP), [groups]);
1289
+ const countOf = (rows) => rows.reduce((count, group) => count + group.skills.length, 0);
1290
+ const connectorCount = connectors.kind === "ready" ? connectors.catalogue.connectors.length : 0;
1291
+ const tabRows = [
1292
+ {
1293
+ value: "builtin",
1294
+ label: t("tab.builtin"),
1295
+ count: countOf(builtinGroups)
1296
+ },
1297
+ {
1298
+ value: "personal",
1299
+ label: t("tab.personal"),
1300
+ count: countOf(personalGroups)
1301
+ },
1302
+ {
1303
+ value: "plaza",
1304
+ label: t("tab.plaza"),
1305
+ count: 0
1306
+ },
1307
+ {
1308
+ value: "connectors",
1309
+ label: t("tab.connectors"),
1310
+ count: connectorCount
1311
+ }
1312
+ ];
429
1313
  const toggle = (0, react.useCallback)(async (skill, enabled) => {
430
1314
  if (skill.path === void 0) return;
431
1315
  try {
@@ -455,6 +1339,168 @@ window.__ModuleLoader__.load({
455
1339
  load,
456
1340
  t
457
1341
  ]);
1342
+ const toggleConnector = (0, react.useCallback)(async (connector, enabled) => {
1343
+ if (connectors.kind !== "ready") return;
1344
+ setConnectorBusyId(connector.id);
1345
+ setConnectorNotice(null);
1346
+ try {
1347
+ if (connectors.catalogue.demo) setConnectors({
1348
+ kind: "ready",
1349
+ catalogue: {
1350
+ demo: true,
1351
+ connectors: connectors.catalogue.connectors.map((row) => row.id === connector.id ? {
1352
+ ...row,
1353
+ enabled,
1354
+ connected: enabled
1355
+ } : row)
1356
+ }
1357
+ });
1358
+ else setConnectors({
1359
+ kind: "ready",
1360
+ catalogue: {
1361
+ demo: false,
1362
+ connectors: await connectorSource.setEnabled(connector.id, enabled)
1363
+ }
1364
+ });
1365
+ } catch (error) {
1366
+ setConnectorNotice(error instanceof Error ? error.message : String(error));
1367
+ } finally {
1368
+ setConnectorBusyId(null);
1369
+ }
1370
+ }, [connectorSource, connectors]);
1371
+ const toggleCapability = (0, react.useCallback)(async (connector, capability, enabled) => {
1372
+ if (connectors.kind !== "ready") return;
1373
+ setConnectorBusyId(connector.id + ":" + capability.id);
1374
+ setConnectorNotice(null);
1375
+ try {
1376
+ if (connectors.catalogue.demo) setConnectors({
1377
+ kind: "ready",
1378
+ catalogue: {
1379
+ demo: true,
1380
+ connectors: connectors.catalogue.connectors.map((row) => row.id === connector.id ? {
1381
+ ...row,
1382
+ capabilities: row.capabilities.map((item) => item.id === capability.id ? {
1383
+ ...item,
1384
+ enabled
1385
+ } : item)
1386
+ } : row)
1387
+ }
1388
+ });
1389
+ else setConnectors({
1390
+ kind: "ready",
1391
+ catalogue: {
1392
+ demo: false,
1393
+ connectors: await connectorSource.setCapability(connector.id, capability.id, enabled)
1394
+ }
1395
+ });
1396
+ } catch (error) {
1397
+ setConnectorNotice(error instanceof Error ? error.message : String(error));
1398
+ } finally {
1399
+ setConnectorBusyId(null);
1400
+ }
1401
+ }, [connectorSource, connectors]);
1402
+ const openShare = (0, react.useCallback)((skill) => {
1403
+ setShareTarget(skill);
1404
+ setShareInstruction("");
1405
+ setShareTags("");
1406
+ setShareError(null);
1407
+ const choice = sanitizeChoice(readSavedScope(window.localStorage, scopeStorageKey(readAccountIdentity())), reviewScope, departments);
1408
+ setShareVisibility(choice.visibility);
1409
+ setShareDepartment(choice.departmentCode);
1410
+ setShareLoading(true);
1411
+ api.content(skill.name, skill.path, scope).then((payload) => {
1412
+ setShareInstruction(payload.content);
1413
+ }).catch((error) => {
1414
+ setShareError(t("plaza.failed") + ": " + (error instanceof Error ? error.message : String(error)));
1415
+ }).finally(() => {
1416
+ setShareLoading(false);
1417
+ });
1418
+ }, [
1419
+ api,
1420
+ departments,
1421
+ reviewScope,
1422
+ scope,
1423
+ t
1424
+ ]);
1425
+ (0, react.useEffect)(() => {
1426
+ if (shareTarget === null || reviewScope === void 0) return;
1427
+ const choice = sanitizeChoice(readSavedScope(window.localStorage, scopeStorageKey(readAccountIdentity())), reviewScope, departments);
1428
+ setShareVisibility(choice.visibility);
1429
+ setShareDepartment(choice.departmentCode);
1430
+ }, [
1431
+ reviewScope,
1432
+ departments,
1433
+ shareTarget
1434
+ ]);
1435
+ const closeShare = (0, react.useCallback)(() => {
1436
+ if (shareBusy) return;
1437
+ setShareTarget(null);
1438
+ setShareError(null);
1439
+ }, [shareBusy]);
1440
+ const submitShare = (0, react.useCallback)(async () => {
1441
+ if (shareTarget === null) return;
1442
+ if (shareInstruction.trim() === "") {
1443
+ setShareError(t("plaza.instruction") + " required");
1444
+ return;
1445
+ }
1446
+ setShareBusy(true);
1447
+ setShareError(null);
1448
+ try {
1449
+ const tags = shareTags.split(/[,,]/u).map((tag) => tag.trim()).filter((tag) => tag !== "");
1450
+ const choice = {
1451
+ visibility: shareVisibility,
1452
+ ...shareVisibility === "department" && shareDepartment !== void 0 ? { departmentCode: shareDepartment } : {}
1453
+ };
1454
+ await api.plazaSubmit({
1455
+ name: shareTarget.name,
1456
+ description: shareTarget.description,
1457
+ instruction: shareInstruction,
1458
+ ...tags.length === 0 ? {} : { tags },
1459
+ ...choice
1460
+ });
1461
+ writeSavedScope(window.localStorage, scopeStorageKey(readAccountIdentity()), choice);
1462
+ setShareTarget(null);
1463
+ await loadPlaza();
1464
+ } catch (error) {
1465
+ const message = error instanceof Error ? error.message : String(error);
1466
+ if (shareVisibility === "global" && /403|forbidden|权限/i.test(message)) {
1467
+ const fallback = sanitizeChoice({ visibility: "department" }, reviewScope, departments);
1468
+ setShareVisibility(fallback.visibility);
1469
+ setShareDepartment(fallback.departmentCode);
1470
+ setShareError(t("plaza.scopeForbidden"));
1471
+ } else setShareError(error instanceof PlazaUnavailableError ? t("plaza.unavailable") : t("plaza.failed") + ": " + message);
1472
+ } finally {
1473
+ setShareBusy(false);
1474
+ }
1475
+ }, [
1476
+ api,
1477
+ departments,
1478
+ loadPlaza,
1479
+ reviewScope,
1480
+ shareDepartment,
1481
+ shareInstruction,
1482
+ shareTags,
1483
+ shareTarget,
1484
+ shareVisibility,
1485
+ t
1486
+ ]);
1487
+ const unshare = (0, react.useCallback)(async (_skill, id) => {
1488
+ if (!window.confirm(t("plaza.unshareConfirm"))) return;
1489
+ setShareBusy(true);
1490
+ setShareError(null);
1491
+ try {
1492
+ await api.plazaUnshare(id);
1493
+ await loadPlaza();
1494
+ } catch (error) {
1495
+ setShareError(error instanceof PlazaUnavailableError ? t("plaza.unavailable") : t("plaza.failed") + ": " + (error instanceof Error ? error.message : String(error)));
1496
+ } finally {
1497
+ setShareBusy(false);
1498
+ }
1499
+ }, [
1500
+ api,
1501
+ loadPlaza,
1502
+ t
1503
+ ]);
458
1504
  /** Bind one draft key to a change handler. */
459
1505
  const set = (0, react.useCallback)((key) => (event) => {
460
1506
  const value = event.target.value;
@@ -492,201 +1538,430 @@ window.__ModuleLoader__.load({
492
1538
  draft,
493
1539
  load
494
1540
  ]);
495
- const total = state.kind === "ready" ? state.payload.groups.reduce((n, g) => n + g.skills.length, 0) : 0;
496
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1541
+ const visibleGroups = tab === "builtin" ? builtinGroups : personalGroups;
1542
+ const visibleTotal = countOf(visibleGroups);
1543
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
497
1544
  className: SkillCenterPage_module_css_default.page,
498
- children: [
499
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
500
- className: SkillCenterPage_module_css_default.pageHead,
501
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
502
- className: SkillCenterPage_module_css_default.pageTitle,
503
- children: t("panel")
504
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
505
- className: SkillCenterPage_module_css_default.toolbar,
506
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1545
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1546
+ className: SkillCenterPage_module_css_default.pageContent,
1547
+ children: [
1548
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
1549
+ className: SkillCenterPage_module_css_default.pageHead,
1550
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
1551
+ className: SkillCenterPage_module_css_default.pageTitle,
1552
+ children: t("panel")
1553
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1554
+ className: SkillCenterPage_module_css_default.toolbar,
1555
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1556
+ type: "button",
1557
+ className: SkillCenterPage_module_css_default.iconButton,
1558
+ "aria-label": t("action.refresh"),
1559
+ title: t("action.refresh"),
1560
+ onClick: () => {
1561
+ load();
1562
+ },
1563
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1564
+ className: SkillCenterPage_module_css_default.iconWrap,
1565
+ "aria-hidden": "true",
1566
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineRegular, {})
1567
+ })
1568
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1569
+ variant: "primary",
1570
+ size: "sm",
1571
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, { size: 13 }),
1572
+ onClick: () => {
1573
+ setCreating((v) => !v);
1574
+ },
1575
+ children: t("action.create")
1576
+ })]
1577
+ })]
1578
+ }),
1579
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1580
+ className: SkillCenterPage_module_css_default.tabs,
1581
+ role: "tablist",
1582
+ "aria-label": t("tab.label"),
1583
+ children: tabRows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
507
1584
  type: "button",
508
- className: SkillCenterPage_module_css_default.iconButton,
509
- "aria-label": t("action.refresh"),
510
- title: t("action.refresh"),
1585
+ role: "tab",
1586
+ id: "skill-center-tab-" + row.value,
1587
+ "aria-selected": tab === row.value,
1588
+ "aria-controls": "skill-center-panel-" + row.value,
1589
+ className: tab === row.value ? SkillCenterPage_module_css_default.tab + " " + SkillCenterPage_module_css_default.tabActive : SkillCenterPage_module_css_default.tab,
1590
+ "data-tab": row.value,
511
1591
  onClick: () => {
512
- load();
1592
+ setTab(row.value);
1593
+ if (row.value === "connectors" && connectors.kind === "failed") loadConnectors();
513
1594
  },
514
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
515
- className: SkillCenterPage_module_css_default.iconWrap,
516
- "aria-hidden": "true",
517
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineRegular, {})
518
- })
1595
+ children: [row.label, row.count === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1596
+ className: SkillCenterPage_module_css_default.tabCount,
1597
+ children: row.count
1598
+ })]
1599
+ }, row.value))
1600
+ }),
1601
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1602
+ open: creating,
1603
+ onClose: () => {
1604
+ setCreating(false);
1605
+ },
1606
+ title: t("create.title"),
1607
+ closeLabel: t("action.cancel"),
1608
+ className: SkillCenterPage_module_css_default.dialog,
1609
+ footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1610
+ variant: "outline",
1611
+ autoFocus: true,
1612
+ onClick: () => {
1613
+ setCreating(false);
1614
+ },
1615
+ children: t("action.cancel")
519
1616
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
520
1617
  variant: "primary",
521
- size: "sm",
522
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, { size: 13 }),
523
1618
  onClick: () => {
524
- setCreating((v) => !v);
1619
+ submit();
525
1620
  },
526
- children: t("action.create")
527
- })]
528
- })]
529
- }),
530
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
531
- open: creating,
532
- onClose: () => {
533
- setCreating(false);
534
- },
535
- title: t("create.title"),
536
- closeLabel: t("action.cancel"),
537
- className: SkillCenterPage_module_css_default.dialog,
538
- footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
539
- variant: "outline",
540
- autoFocus: true,
541
- onClick: () => {
542
- setCreating(false);
543
- },
544
- children: t("action.cancel")
545
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
546
- variant: "primary",
547
- onClick: () => {
548
- submit();
549
- },
550
- children: t("action.confirm")
551
- })] }),
552
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
553
- className: SkillCenterPage_module_css_default.form,
554
- children: [
555
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
556
- label: t("create.name"),
557
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
558
- className: SkillCenterPage_module_css_default.input,
559
- value: draft.name,
560
- onChange: set("name")
1621
+ children: t("action.confirm")
1622
+ })] }),
1623
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1624
+ className: SkillCenterPage_module_css_default.form,
1625
+ children: [
1626
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
1627
+ label: t("create.name"),
1628
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1629
+ className: SkillCenterPage_module_css_default.input,
1630
+ value: draft.name,
1631
+ onChange: set("name")
1632
+ })
1633
+ }),
1634
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
1635
+ label: t("create.description"),
1636
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1637
+ className: SkillCenterPage_module_css_default.input,
1638
+ value: draft.description,
1639
+ onChange: set("description")
1640
+ })
1641
+ }),
1642
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
1643
+ label: t("create.whenToUse"),
1644
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1645
+ className: SkillCenterPage_module_css_default.input,
1646
+ value: draft.whenToUse,
1647
+ onChange: set("whenToUse")
1648
+ })
1649
+ }),
1650
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
1651
+ label: t("create.content"),
1652
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1653
+ className: SkillCenterPage_module_css_default.textarea,
1654
+ value: draft.content,
1655
+ onChange: set("content")
1656
+ })
1657
+ }),
1658
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
1659
+ label: t("create.root"),
1660
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1661
+ className: SkillCenterPage_module_css_default.input,
1662
+ value: draft.root,
1663
+ onChange: (e) => {
1664
+ setDraft((d) => ({
1665
+ ...d,
1666
+ root: e.target.value === "project" ? "project" : "user"
1667
+ }));
1668
+ },
1669
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1670
+ value: "user",
1671
+ children: t("create.rootUser")
1672
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1673
+ value: "project",
1674
+ children: t("create.rootProject")
1675
+ })]
1676
+ })
561
1677
  })
1678
+ ]
1679
+ })
1680
+ }),
1681
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1682
+ open: shareTarget !== null,
1683
+ onClose: closeShare,
1684
+ title: t("plaza.dialogTitle"),
1685
+ headless: true,
1686
+ className: SkillCenterPage_module_css_default.publishDialog,
1687
+ children: [
1688
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
1689
+ className: SkillCenterPage_module_css_default.dialogHeader,
1690
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
1691
+ className: SkillCenterPage_module_css_default.dialogTitle,
1692
+ children: t("plaza.dialogTitle")
1693
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1694
+ type: "button",
1695
+ className: SkillCenterPage_module_css_default.dialogClose,
1696
+ "aria-label": t("action.close"),
1697
+ onClick: closeShare,
1698
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
1699
+ })]
562
1700
  }),
563
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
564
- label: t("create.description"),
565
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
566
- className: SkillCenterPage_module_css_default.input,
567
- value: draft.description,
568
- onChange: set("description")
1701
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1702
+ className: SkillCenterPage_module_css_default.dialogBody,
1703
+ "data-publish-body": true,
1704
+ children: shareTarget === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1705
+ className: SkillCenterPage_module_css_default.form,
1706
+ "data-share-dialog": shareTarget.name,
1707
+ children: [
1708
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
1709
+ label: t("create.name"),
1710
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1711
+ className: SkillCenterPage_module_css_default.input,
1712
+ value: shareTarget.name,
1713
+ readOnly: true
1714
+ })
1715
+ }),
1716
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
1717
+ label: t("create.description"),
1718
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1719
+ className: SkillCenterPage_module_css_default.input,
1720
+ value: shareTarget.description,
1721
+ readOnly: true
1722
+ })
1723
+ }),
1724
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
1725
+ label: t("plaza.tags"),
1726
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1727
+ className: SkillCenterPage_module_css_default.input,
1728
+ value: shareTags,
1729
+ placeholder: t("plaza.tagsPlaceholder"),
1730
+ onChange: (event) => {
1731
+ setShareTags(event.target.value);
1732
+ }
1733
+ })
1734
+ }),
1735
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
1736
+ label: t("plaza.visibility"),
1737
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1738
+ className: SkillCenterPage_module_css_default.input,
1739
+ value: shareVisibility,
1740
+ "data-share-visibility": true,
1741
+ onChange: (event) => {
1742
+ const visibility = event.target.value;
1743
+ setShareVisibility(visibility);
1744
+ if (visibility === "department") setShareDepartment(shareDepartment ?? ownCode ?? selectableDepartments[0]?.code);
1745
+ },
1746
+ children: [
1747
+ visibilityOptions.includes("global") ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1748
+ value: "global",
1749
+ children: t("plaza.visibilityGlobal")
1750
+ }) : null,
1751
+ visibilityOptions.includes("department") ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1752
+ value: "department",
1753
+ children: t("plaza.visibilityDepartment")
1754
+ }) : null,
1755
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1756
+ value: "private",
1757
+ children: t("plaza.visibilityPrivate")
1758
+ })
1759
+ ]
1760
+ })
1761
+ }),
1762
+ shareVisibility === "department" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
1763
+ label: t("plaza.department"),
1764
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
1765
+ className: SkillCenterPage_module_css_default.input,
1766
+ value: shareDepartment ?? selectableDepartments[0]?.code ?? "",
1767
+ "data-share-department": true,
1768
+ disabled: role !== "admin" || selectableDepartments.length <= 1,
1769
+ onChange: (event) => {
1770
+ setShareDepartment(event.target.value);
1771
+ },
1772
+ children: selectableDepartments.map((department) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1773
+ value: department.code,
1774
+ children: department.name
1775
+ }, department.code))
1776
+ })
1777
+ }) : null,
1778
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1779
+ className: SkillCenterPage_module_css_default.plazaScopeHint,
1780
+ children: role === "admin" ? t("plaza.scopeHintAdmin") : t("plaza.scopeHintUser")
1781
+ }),
1782
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
1783
+ label: t("plaza.instruction"),
1784
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1785
+ className: SkillCenterPage_module_css_default.textarea,
1786
+ value: shareInstruction,
1787
+ readOnly: shareLoading,
1788
+ placeholder: shareLoading ? t("plaza.contentLoading") : void 0,
1789
+ onChange: (event) => {
1790
+ setShareInstruction(event.target.value);
1791
+ }
1792
+ })
1793
+ }),
1794
+ shareError === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1795
+ className: SkillCenterPage_module_css_default.status + " " + SkillCenterPage_module_css_default.statusError,
1796
+ role: "alert",
1797
+ children: shareError
1798
+ })
1799
+ ]
569
1800
  })
570
1801
  }),
571
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
572
- label: t("create.whenToUse"),
573
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
574
- className: SkillCenterPage_module_css_default.input,
575
- value: draft.whenToUse,
576
- onChange: set("whenToUse")
577
- })
1802
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
1803
+ className: SkillCenterPage_module_css_default.dialogFooter,
1804
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1805
+ variant: "outline",
1806
+ disabled: shareBusy,
1807
+ onClick: closeShare,
1808
+ children: t("action.cancel")
1809
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1810
+ variant: "primary",
1811
+ disabled: shareBusy || shareLoading,
1812
+ onClick: () => {
1813
+ submitShare();
1814
+ },
1815
+ children: t("plaza.submit")
1816
+ })]
1817
+ })
1818
+ ]
1819
+ }),
1820
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1821
+ className: SkillCenterPage_module_css_default.searchField,
1822
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
1823
+ type: "search",
1824
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutlineRegular, {}),
1825
+ placeholder: tab === "connectors" ? t("search.connectorPlaceholder") : t("search.placeholder"),
1826
+ "aria-label": tab === "connectors" ? t("search.connectorPlaceholder") : t("search.placeholder"),
1827
+ value: query,
1828
+ onChange: (e) => {
1829
+ setQuery(e.target.value);
1830
+ }
1831
+ }), query === "" ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1832
+ size: "sm",
1833
+ variant: "ghost",
1834
+ className: SkillCenterPage_module_css_default.searchClear,
1835
+ "aria-label": t("search.clear"),
1836
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, {}),
1837
+ onClick: () => {
1838
+ setQuery("");
1839
+ }
1840
+ })]
1841
+ }),
1842
+ tab !== "connectors" && plaza.kind === "unavailable" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1843
+ className: SkillCenterPage_module_css_default.status,
1844
+ role: "status",
1845
+ "data-plaza-unavailable": true,
1846
+ children: t("plaza.unavailable")
1847
+ }) : null,
1848
+ shareError !== null && shareTarget === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1849
+ className: SkillCenterPage_module_css_default.status + " " + SkillCenterPage_module_css_default.statusError,
1850
+ role: "alert",
1851
+ children: shareError
1852
+ }) : null,
1853
+ connectorNotice === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1854
+ className: SkillCenterPage_module_css_default.status + " " + SkillCenterPage_module_css_default.statusError,
1855
+ role: "alert",
1856
+ children: connectorNotice
1857
+ }),
1858
+ (tab === "builtin" || tab === "personal") && progress !== void 0 && progress.done < progress.total ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1859
+ className: SkillCenterPage_module_css_default.progressRow,
1860
+ children: [
1861
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1862
+ className: SkillCenterPage_module_css_default.progressLabel,
1863
+ children: t("translate.label")
578
1864
  }),
579
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
580
- label: t("create.content"),
581
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
582
- className: SkillCenterPage_module_css_default.textarea,
583
- value: draft.content,
584
- onChange: set("content")
1865
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1866
+ className: SkillCenterPage_module_css_default.progressTrack,
1867
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1868
+ className: SkillCenterPage_module_css_default.progressFill,
1869
+ style: { width: String(progress.total === 0 ? 0 : Math.round(progress.done / progress.total * 100)) + "%" }
585
1870
  })
586
1871
  }),
587
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftField, {
588
- label: t("create.root"),
589
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
590
- className: SkillCenterPage_module_css_default.input,
591
- value: draft.root,
592
- onChange: (e) => {
593
- setDraft((d) => ({
594
- ...d,
595
- root: e.target.value === "project" ? "project" : "user"
596
- }));
597
- },
598
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
599
- value: "user",
600
- children: t("create.rootUser")
601
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
602
- value: "project",
603
- children: t("create.rootProject")
604
- })]
605
- })
1872
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1873
+ className: SkillCenterPage_module_css_default.progressCount,
1874
+ children: [
1875
+ progress.done,
1876
+ " / ",
1877
+ progress.total
1878
+ ]
606
1879
  })
607
1880
  ]
1881
+ }) : null,
1882
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1883
+ className: SkillCenterPage_module_css_default.tabPanel,
1884
+ id: "skill-center-panel-" + tab,
1885
+ role: "tabpanel",
1886
+ "aria-labelledby": "skill-center-tab-" + tab,
1887
+ "data-tab-panel": tab,
1888
+ children: [
1889
+ tab === "builtin" || tab === "personal" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1890
+ state.kind === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1891
+ className: SkillCenterPage_module_css_default.status,
1892
+ children: t("state.loading")
1893
+ }) : null,
1894
+ state.kind === "failed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1895
+ className: SkillCenterPage_module_css_default.status + " " + SkillCenterPage_module_css_default.statusError,
1896
+ children: [
1897
+ t("state.failed"),
1898
+ ": ",
1899
+ state.message
1900
+ ]
1901
+ }) : null,
1902
+ state.kind === "ready" && visibleTotal === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1903
+ className: SkillCenterPage_module_css_default.status,
1904
+ children: query.trim() === "" ? t("state.empty") : t("search.noMatches")
1905
+ }) : null,
1906
+ visibleGroups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1907
+ className: SkillCenterPage_module_css_default.group,
1908
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
1909
+ className: SkillCenterPage_module_css_default.groupTitle,
1910
+ children: [group.title, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1911
+ className: SkillCenterPage_module_css_default.groupCount,
1912
+ children: group.skills.length
1913
+ })]
1914
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
1915
+ className: SkillCenterPage_module_css_default.cards,
1916
+ children: group.skills.map((skill) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SkillCard, {
1917
+ skill,
1918
+ api,
1919
+ cwd: state.kind === "ready" ? state.payload.cwd : scope,
1920
+ t,
1921
+ share: shareOf(skill.name, plazaRecords),
1922
+ shareBusy,
1923
+ shareDisabled: plaza.kind === "unavailable",
1924
+ onToggle: (s, enabled) => {
1925
+ toggle(s, enabled);
1926
+ },
1927
+ onDelete: (s) => {
1928
+ remove(s);
1929
+ },
1930
+ onShare: openShare,
1931
+ onUnshare: (s, id) => {
1932
+ unshare(s, id);
1933
+ }
1934
+ }, group.key + ":" + skill.name))
1935
+ })]
1936
+ }, group.key))
1937
+ ] }) : null,
1938
+ tab === "plaza" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1939
+ className: SkillCenterPage_module_css_default.plazaPanel,
1940
+ "data-plaza-panel": true,
1941
+ children: renderSlot("skill-center.section", { query }, { fallback: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1942
+ className: SkillCenterPage_module_css_default.status,
1943
+ children: t("plaza.sectionFallback")
1944
+ }) })
1945
+ }) : null,
1946
+ tab === "connectors" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConnectorsTab, {
1947
+ state: connectors,
1948
+ query,
1949
+ busyId: connectorBusyId,
1950
+ t,
1951
+ onRetry: () => {
1952
+ loadConnectors();
1953
+ },
1954
+ onToggleConnector: (connector, enabled) => {
1955
+ toggleConnector(connector, enabled);
1956
+ },
1957
+ onToggleCapability: (connector, capability, enabled) => {
1958
+ toggleCapability(connector, capability, enabled);
1959
+ }
1960
+ }) : null
1961
+ ]
608
1962
  })
609
- }),
610
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
611
- className: SkillCenterPage_module_css_default.search,
612
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutlineRegular, {}),
613
- placeholder: t("search.placeholder"),
614
- "aria-label": t("search.placeholder"),
615
- value: query,
616
- onChange: (e) => {
617
- setQuery(e.target.value);
618
- }
619
- }),
620
- progress === void 0 || progress.done >= progress.total ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
621
- className: SkillCenterPage_module_css_default.progressRow,
622
- children: [
623
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
624
- className: SkillCenterPage_module_css_default.progressLabel,
625
- children: t("translate.label")
626
- }),
627
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
628
- className: SkillCenterPage_module_css_default.progressTrack,
629
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
630
- className: SkillCenterPage_module_css_default.progressFill,
631
- style: { width: String(progress.total === 0 ? 0 : Math.round(progress.done / progress.total * 100)) + "%" }
632
- })
633
- }),
634
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
635
- className: SkillCenterPage_module_css_default.progressCount,
636
- children: [
637
- progress.done,
638
- " / ",
639
- progress.total
640
- ]
641
- })
642
- ]
643
- }),
644
- state.kind === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
645
- className: SkillCenterPage_module_css_default.status,
646
- children: t("state.loading")
647
- }) : null,
648
- state.kind === "failed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
649
- className: SkillCenterPage_module_css_default.status + " " + SkillCenterPage_module_css_default.statusError,
650
- children: [
651
- t("state.failed"),
652
- ": ",
653
- state.message
654
- ]
655
- }) : null,
656
- state.kind === "ready" && groups.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
657
- className: SkillCenterPage_module_css_default.status,
658
- children: query.trim() === "" ? t("state.empty") : t("search.noMatches")
659
- }) : null,
660
- state.kind === "ready" && groups.length > 0 && total === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
661
- className: SkillCenterPage_module_css_default.status,
662
- children: t("state.empty")
663
- }) : null,
664
- groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
665
- className: SkillCenterPage_module_css_default.group,
666
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
667
- className: SkillCenterPage_module_css_default.groupTitle,
668
- children: [group.title, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
669
- className: SkillCenterPage_module_css_default.groupCount,
670
- children: group.skills.length
671
- })]
672
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
673
- className: SkillCenterPage_module_css_default.cards,
674
- children: group.skills.map((skill) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SkillCard, {
675
- skill,
676
- api,
677
- cwd: state.kind === "ready" ? state.payload.cwd : scope,
678
- t,
679
- onToggle: (s, enabled) => {
680
- toggle(s, enabled);
681
- },
682
- onDelete: (s) => {
683
- remove(s);
684
- }
685
- }, group.key + ":" + skill.name))
686
- })]
687
- }, group.key)),
688
- renderSlot("skill-center.section", { query })
689
- ]
1963
+ ]
1964
+ })
690
1965
  });
691
1966
  }
692
1967
  //#endregion
@@ -704,8 +1979,15 @@ window.__ModuleLoader__.load({
704
1979
  /** Simplified Chinese dictionary. */
705
1980
  const zh = {
706
1981
  "panel": "技能中心",
1982
+ "tab.label": "技能分类",
1983
+ "tab.builtin": "内置",
1984
+ "tab.personal": "个人",
1985
+ "tab.plaza": "技能广场",
1986
+ "tab.connectors": "连接器",
707
1987
  "search.placeholder": "搜索技能…",
1988
+ "search.connectorPlaceholder": "搜索连接器…",
708
1989
  "search.noMatches": "无匹配技能",
1990
+ "search.clear": "清空搜索",
709
1991
  "action.refresh": "刷新",
710
1992
  "action.create": "新建技能",
711
1993
  "action.delete": "删除",
@@ -737,13 +2019,64 @@ window.__ModuleLoader__.load({
737
2019
  "create.root": "位置",
738
2020
  "create.rootUser": "用户级",
739
2021
  "create.rootProject": "项目级",
740
- "delete.confirm": "删除后可从 .trash 恢复。确定删除?"
2022
+ "delete.confirm": "删除后可从 .trash 恢复。确定删除?",
2023
+ "plaza.statusLocal": "未共享",
2024
+ "plaza.statusPending": "待审核",
2025
+ "plaza.statusApproved": "已上架",
2026
+ "plaza.statusRejected": "已驳回",
2027
+ "plaza.sharedTag": "已共享",
2028
+ "plaza.share": "上架",
2029
+ "plaza.resubmit": "重新提交",
2030
+ "plaza.unshare": "取消共享",
2031
+ "plaza.unavailable": "共享服务未就绪,暂时无法上架",
2032
+ "plaza.failed": "共享操作失败",
2033
+ "plaza.dialogTitle": "上架到技能广场",
2034
+ "plaza.tags": "标签",
2035
+ "plaza.tagsPlaceholder": "用逗号分隔,例如:数据,SQL",
2036
+ "plaza.instruction": "技能内容",
2037
+ "plaza.submit": "提交审核",
2038
+ "plaza.unshareConfirm": "确定取消共享?",
2039
+ "plaza.reason": "审核意见",
2040
+ "plaza.contentLoading": "正在读取技能内容…",
2041
+ "plaza.visibility": "可见范围",
2042
+ "plaza.visibilityGlobal": "全局(所有人可见)",
2043
+ "plaza.visibilityDepartment": "部门专属",
2044
+ "plaza.visibilityPrivate": "私有(仅自己可见)",
2045
+ "plaza.department": "部门",
2046
+ "plaza.scopeForbidden": "无权选择该范围,请改用部门专属或私有",
2047
+ "plaza.scopeHintAdmin": "超管/管理员可选全局或任意部门",
2048
+ "plaza.scopeHintUser": "普通用户/部门管理员只能选本部门或私有",
2049
+ "plaza.sectionFallback": "技能广场服务未就绪,暂时无法浏览",
2050
+ "connector.loading": "正在加载连接器…",
2051
+ "connector.failed": "连接器加载失败",
2052
+ "connector.retry": "重试",
2053
+ "connector.demo": "当前显示示例连接器,后端接入后自动替换",
2054
+ "connector.demoTag": "示例",
2055
+ "connector.enabled": "已启用",
2056
+ "connector.disabled": "未启用",
2057
+ "connector.connected": "已连接",
2058
+ "connector.error": "连接异常",
2059
+ "connector.enable": "启用",
2060
+ "connector.disable": "停用",
2061
+ "connector.capabilities": "能力",
2062
+ "connector.noCapabilities": "当前账号没有可用的连接器能力",
2063
+ "connector.empty": "暂无连接器",
2064
+ "connector.noMatches": "无匹配连接器",
2065
+ "connector.unavailable": "暂不可用",
2066
+ "connector.busy": "处理中…"
741
2067
  };
742
2068
  /** English dictionary. */
743
2069
  const en = {
744
2070
  "panel": "Skill Center",
2071
+ "tab.label": "Skill sections",
2072
+ "tab.builtin": "Built-in",
2073
+ "tab.personal": "Personal",
2074
+ "tab.plaza": "Skill plaza",
2075
+ "tab.connectors": "Connectors",
745
2076
  "search.placeholder": "Search skills…",
2077
+ "search.connectorPlaceholder": "Search connectors…",
746
2078
  "search.noMatches": "No matching skills",
2079
+ "search.clear": "Clear search",
747
2080
  "action.refresh": "Refresh",
748
2081
  "action.create": "New skill",
749
2082
  "action.delete": "Delete",
@@ -775,7 +2108,51 @@ window.__ModuleLoader__.load({
775
2108
  "create.root": "Location",
776
2109
  "create.rootUser": "User",
777
2110
  "create.rootProject": "Project",
778
- "delete.confirm": "Deleting moves it into .trash, where it can be restored. Delete?"
2111
+ "delete.confirm": "Deleting moves it into .trash, where it can be restored. Delete?",
2112
+ "plaza.statusLocal": "Local",
2113
+ "plaza.statusPending": "Pending review",
2114
+ "plaza.statusApproved": "Published",
2115
+ "plaza.statusRejected": "Rejected",
2116
+ "plaza.sharedTag": "Shared",
2117
+ "plaza.share": "Publish",
2118
+ "plaza.resubmit": "Resubmit",
2119
+ "plaza.unshare": "Unshare",
2120
+ "plaza.unavailable": "Sharing service is not ready; publishing is disabled",
2121
+ "plaza.failed": "Sharing action failed",
2122
+ "plaza.dialogTitle": "Publish to skill plaza",
2123
+ "plaza.tags": "Tags",
2124
+ "plaza.tagsPlaceholder": "Comma separated, e.g. data, SQL",
2125
+ "plaza.instruction": "Skill content",
2126
+ "plaza.submit": "Submit for review",
2127
+ "plaza.unshareConfirm": "Stop sharing this skill?",
2128
+ "plaza.reason": "Review note",
2129
+ "plaza.contentLoading": "Loading skill content…",
2130
+ "plaza.visibility": "Visibility",
2131
+ "plaza.visibilityGlobal": "Global (everyone)",
2132
+ "plaza.visibilityDepartment": "Department only",
2133
+ "plaza.visibilityPrivate": "Private (only me)",
2134
+ "plaza.department": "Department",
2135
+ "plaza.scopeForbidden": "You cannot use that visibility; pick department or private",
2136
+ "plaza.scopeHintAdmin": "Super admins/admins may publish globally or to any department",
2137
+ "plaza.scopeHintUser": "Users and department admins may publish to their own department or privately",
2138
+ "plaza.sectionFallback": "The skill plaza is not available yet",
2139
+ "connector.loading": "Loading connectors…",
2140
+ "connector.failed": "Could not load connectors",
2141
+ "connector.retry": "Retry",
2142
+ "connector.demo": "Showing demo connectors until the backend supplies the catalogue",
2143
+ "connector.demoTag": "Demo",
2144
+ "connector.enabled": "Enabled",
2145
+ "connector.disabled": "Disabled",
2146
+ "connector.connected": "Connected",
2147
+ "connector.error": "Connection error",
2148
+ "connector.enable": "Enable",
2149
+ "connector.disable": "Disable",
2150
+ "connector.capabilities": "Capabilities",
2151
+ "connector.noCapabilities": "This account has no available connector capabilities",
2152
+ "connector.empty": "No connectors",
2153
+ "connector.noMatches": "No matching connectors",
2154
+ "connector.unavailable": "Unavailable",
2155
+ "connector.busy": "Working…"
779
2156
  };
780
2157
  //#endregion
781
2158
  //#region src/client/index.ts