create-principles-disciple 1.101.0 → 1.103.0
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/console/dist/server/config/pd-config-store.d.ts +50 -1
- package/console/dist/server/config/pd-config-store.js +364 -1
- package/console/dist/server/index.js +9 -0
- package/console/dist/server/models/ActivationsConsoleModel.d.ts +44 -5
- package/console/dist/server/models/ActivationsConsoleModel.js +118 -16
- package/console/dist/server/routes/config.js +92 -2
- package/console/dist/server/routes/onboarding.d.ts +34 -0
- package/console/dist/server/routes/onboarding.js +324 -0
- package/console/dist/ui/App.js +74 -15
- package/console/dist/ui/api.d.ts +60 -3
- package/console/dist/ui/api.js +63 -2
- package/console/dist/ui/components/onboarding/CircuitDiagram.d.ts +8 -0
- package/console/dist/ui/components/onboarding/CircuitDiagram.js +18 -0
- package/console/dist/ui/components/onboarding/DemoResultView.d.ts +22 -0
- package/console/dist/ui/components/onboarding/DemoResultView.js +33 -0
- package/console/dist/ui/i18n/en.json +189 -1
- package/console/dist/ui/i18n/zh-CN.json +189 -1
- package/console/dist/ui/pages/activation/ActivationPage.js +11 -11
- package/console/dist/ui/pages/activation/ActivationValidators.js +15 -14
- package/console/dist/ui/pages/control-center/AgentCard.js +66 -10
- package/console/dist/ui/pages/control-center/ControlCenterPage.js +3 -2
- package/console/dist/ui/pages/control-center/RuntimeProfileManager.d.ts +31 -0
- package/console/dist/ui/pages/control-center/RuntimeProfileManager.js +234 -0
- package/console/dist/ui/pages/debt/DebtPage.js +2 -2
- package/console/dist/ui/pages/settings/SettingsPage.js +64 -5
- package/console/dist/ui/pages/signal-keywords/KeywordEditDialog.d.ts +12 -0
- package/console/dist/ui/pages/signal-keywords/KeywordEditDialog.js +41 -0
- package/console/dist/ui/pages/signal-keywords/KeywordListSection.d.ts +10 -0
- package/console/dist/ui/pages/signal-keywords/KeywordListSection.js +39 -0
- package/console/dist/ui/pages/signal-keywords/PendingTermsSection.d.ts +14 -0
- package/console/dist/ui/pages/signal-keywords/PendingTermsSection.js +35 -0
- package/console/dist/ui/pages/signal-keywords/SignalKeywordsPage.d.ts +1 -0
- package/console/dist/ui/pages/signal-keywords/SignalKeywordsPage.js +49 -0
- package/console/dist/ui/pages/welcome/WelcomePage.d.ts +5 -0
- package/console/dist/ui/pages/welcome/WelcomePage.js +185 -0
- package/console/dist/ui/utils/__tests__/onboarding-state.test.d.ts +1 -0
- package/console/dist/ui/utils/__tests__/onboarding-state.test.js +72 -0
- package/console/dist/ui/utils/agent-metadata.d.ts +13 -0
- package/console/dist/ui/utils/agent-metadata.js +26 -0
- package/console/dist/ui/utils/onboarding-state.d.ts +25 -0
- package/console/dist/ui/utils/onboarding-state.js +77 -0
- package/console/dist/ui/utils/signal-keywords-api.d.ts +68 -0
- package/console/dist/ui/utils/signal-keywords-api.js +121 -0
- package/console/dist/ui/utils/signal-keywords-types.d.ts +57 -0
- package/console/dist/ui/utils/signal-keywords-types.js +10 -0
- package/console/dist/ui/utils/signal-keywords-validators.d.ts +20 -0
- package/console/dist/ui/utils/signal-keywords-validators.js +114 -0
- package/console/dist/ui/utils/validators.d.ts +26 -3
- package/console/dist/ui/utils/validators.js +23 -6
- package/console/dist/web/assets/app.css +442 -0
- package/console/dist/web/assets/app.js +7793 -1966
- package/core/dist/index.d.ts +2 -0
- package/core/dist/index.d.ts.map +1 -1
- package/core/dist/index.js +1 -0
- package/core/dist/index.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +14 -2
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/evaluator-runner-vslice-v2.test.js +28 -0
- package/core/dist/runtime-v2/__tests__/evaluator-runner-vslice-v2.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/pain-to-principle-service.test.js +8 -0
- package/core/dist/runtime-v2/__tests__/pain-to-principle-service.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/resolve-runtime-config-from-pd-config.test.js +8 -10
- package/core/dist/runtime-v2/__tests__/resolve-runtime-config-from-pd-config.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/index.d.ts +1 -1
- package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/index.js +1 -1
- package/core/dist/runtime-v2/activation/index.js.map +1 -1
- package/core/dist/runtime-v2/activation/writers/__tests__/rule-host-writer.test.js +240 -1
- package/core/dist/runtime-v2/activation/writers/__tests__/rule-host-writer.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.d.ts +12 -0
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.js +81 -1
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.js.map +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/l2-resolve-model-compat.test.d.ts +2 -0
- package/core/dist/runtime-v2/adapter/__tests__/l2-resolve-model-compat.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/adapter/__tests__/l2-resolve-model-compat.test.js +81 -0
- package/core/dist/runtime-v2/adapter/__tests__/l2-resolve-model-compat.test.js.map +1 -0
- package/core/dist/runtime-v2/adapter/__tests__/pi-ai-runtime-adapter.test.js +19 -0
- package/core/dist/runtime-v2/adapter/__tests__/pi-ai-runtime-adapter.test.js.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts +8 -0
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +4 -1
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
- package/core/dist/runtime-v2/candidate-intake-service.d.ts.map +1 -1
- package/core/dist/runtime-v2/candidate-intake-service.js +92 -6
- package/core/dist/runtime-v2/candidate-intake-service.js.map +1 -1
- package/core/dist/runtime-v2/candidate-intake.d.ts +38 -0
- package/core/dist/runtime-v2/candidate-intake.d.ts.map +1 -1
- package/core/dist/runtime-v2/candidate-intake.js +48 -0
- package/core/dist/runtime-v2/candidate-intake.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/internal-agent-names.test.d.ts +2 -0
- package/core/dist/runtime-v2/config/__tests__/internal-agent-names.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/config/__tests__/internal-agent-names.test.js +15 -0
- package/core/dist/runtime-v2/config/__tests__/internal-agent-names.test.js.map +1 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js +33 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js +10 -5
- package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-redaction-deep.test.js +1 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-redaction-deep.test.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-validation-edge-cases.test.js +54 -33
- package/core/dist/runtime-v2/config/__tests__/pd-config-validation-edge-cases.test.js.map +1 -1
- package/core/dist/runtime-v2/config/index.d.ts +5 -3
- package/core/dist/runtime-v2/config/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/index.js +8 -2
- package/core/dist/runtime-v2/config/index.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-agent-binding.d.ts +2 -0
- package/core/dist/runtime-v2/config/pd-config-agent-binding.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-agent-binding.js +3 -0
- package/core/dist/runtime-v2/config/pd-config-agent-binding.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.d.ts +8 -3
- package/core/dist/runtime-v2/config/pd-config-defaults.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.js +39 -3
- package/core/dist/runtime-v2/config/pd-config-defaults.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-effective.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-effective.js +25 -1
- package/core/dist/runtime-v2/config/pd-config-effective.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-redaction.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-redaction.js +14 -2
- package/core/dist/runtime-v2/config/pd-config-redaction.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-types.d.ts +116 -1
- package/core/dist/runtime-v2/config/pd-config-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-types.js +7 -0
- package/core/dist/runtime-v2/config/pd-config-types.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-validate.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-validate.js +125 -7
- package/core/dist/runtime-v2/config/pd-config-validate.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-profile-constants.d.ts +27 -0
- package/core/dist/runtime-v2/config/pd-profile-constants.d.ts.map +1 -0
- package/core/dist/runtime-v2/config/pd-profile-constants.js +145 -0
- package/core/dist/runtime-v2/config/pd-profile-constants.js.map +1 -0
- package/core/dist/runtime-v2/config/pd-validate-profile.d.ts +28 -0
- package/core/dist/runtime-v2/config/pd-validate-profile.d.ts.map +1 -0
- package/core/dist/runtime-v2/config/pd-validate-profile.js +482 -0
- package/core/dist/runtime-v2/config/pd-validate-profile.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +26 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +8 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +7 -4
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +5 -2
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder-v2.test.js +32 -0
- package/core/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder-v2.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/artificer-rule-output.test.js +139 -0
- package/core/dist/runtime-v2/internalization/__tests__/artificer-rule-output.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/diag-chain-e2e.test.js +20 -1
- package/core/dist/runtime-v2/internalization/__tests__/diag-chain-e2e.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-intent-tension.test.js +7 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-intent-tension.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-runner.test.js +7 -6
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-runner.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/internalization-task-guards.test.js +1 -53
- package/core/dist/runtime-v2/internalization/__tests__/internalization-task-guards.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/rule-host-input-builder.test.js +23 -0
- package/core/dist/runtime-v2/internalization/__tests__/rule-host-input-builder.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-output.d.ts +7 -0
- package/core/dist/runtime-v2/internalization/artificer-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-output.js +22 -1
- package/core/dist/runtime-v2/internalization/artificer-output.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js +2 -0
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-runner.js +13 -0
- package/core/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-distiller-runner.js +4 -4
- package/core/dist/runtime-v2/internalization/diag-distiller-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.js +5 -5
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-router-runner.js +4 -4
- package/core/dist/runtime-v2/internalization/diag-router-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.js +7 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/index.d.ts +1 -1
- package/core/dist/runtime-v2/internalization/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/index.js +1 -1
- package/core/dist/runtime-v2/internalization/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-task-guards.d.ts +0 -19
- package/core/dist/runtime-v2/internalization/internalization-task-guards.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-task-guards.js +1 -29
- package/core/dist/runtime-v2/internalization/internalization-task-guards.js.map +1 -1
- package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts +2 -0
- package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-runtime-factory.js +2 -0
- package/core/dist/runtime-v2/pain-signal-runtime-factory.js.map +1 -1
- package/core/dist/runtime-v2/signal-collector/__tests__/keyword-stage.test.d.ts +2 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/keyword-stage.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/keyword-stage.test.js +39 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/keyword-stage.test.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/llm-stage.test.d.ts +2 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/llm-stage.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/llm-stage.test.js +34 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/llm-stage.test.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/signal-collector.test.d.ts +2 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/signal-collector.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/signal-collector.test.js +222 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/signal-collector.test.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/types.test.d.ts +2 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/types.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/types.test.js +35 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/types.test.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/index.d.ts +5 -0
- package/core/dist/runtime-v2/signal-collector/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/index.js +5 -0
- package/core/dist/runtime-v2/signal-collector/index.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/keyword-stage.d.ts +20 -0
- package/core/dist/runtime-v2/signal-collector/keyword-stage.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/keyword-stage.js +61 -0
- package/core/dist/runtime-v2/signal-collector/keyword-stage.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/llm-stage.d.ts +16 -0
- package/core/dist/runtime-v2/signal-collector/llm-stage.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/llm-stage.js +34 -0
- package/core/dist/runtime-v2/signal-collector/llm-stage.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/signal-collector.d.ts +16 -0
- package/core/dist/runtime-v2/signal-collector/signal-collector.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/signal-collector.js +71 -0
- package/core/dist/runtime-v2/signal-collector/signal-collector.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/types.d.ts +61 -0
- package/core/dist/runtime-v2/signal-collector/types.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/types.js +45 -0
- package/core/dist/runtime-v2/signal-collector/types.js.map +1 -0
- package/core/dist/runtime-v2/store/schema-conformance.test.js +43 -0
- package/core/dist/runtime-v2/store/schema-conformance.test.js.map +1 -1
- package/core/dist/runtime-v2/types/event-types.d.ts +40 -3
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js +9 -0
- package/core/dist/runtime-v2/types/event-types.js.map +1 -1
- package/core/dist/runtime-v2/types/index.d.ts +2 -2
- package/core/dist/runtime-v2/types/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/index.js +1 -1
- package/core/dist/runtime-v2/types/index.js.map +1 -1
- package/core/dist/workflow-funnel-loader.js +1 -1
- package/core/dist/workflow-funnel-loader.js.map +1 -1
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +6 -0
- package/dist/i18n.js.map +1 -1
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/dist/installer.d.ts +3 -0
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +150 -1
- package/dist/installer.js.map +1 -1
- package/dist/mvp-config.d.ts +8 -0
- package/dist/mvp-config.d.ts.map +1 -1
- package/dist/mvp-config.js +34 -12
- package/dist/mvp-config.js.map +1 -1
- package/package.json +1 -1
- package/pd-cli/dist/commands/__tests__/runtime-probe-config.test.js +2 -2
- package/pd-cli/dist/commands/__tests__/runtime-probe-config.test.js.map +1 -1
- package/pd-cli/dist/commands/demo-story-a.d.ts.map +1 -1
- package/pd-cli/dist/commands/demo-story-a.js +4 -2
- package/pd-cli/dist/commands/demo-story-a.js.map +1 -1
- package/pd-cli/dist/commands/proven-channel-baseline.d.ts.map +1 -1
- package/pd-cli/dist/commands/proven-channel-baseline.js +4 -2
- package/pd-cli/dist/commands/proven-channel-baseline.js.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.d.ts +4 -0
- package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.js +187 -10
- package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
- package/pd-cli/dist/commands/runtime-canary.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-canary.js +4 -2
- package/pd-cli/dist/commands/runtime-canary.js.map +1 -1
- package/pd-cli/dist/commands/runtime-health-snapshot.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-health-snapshot.js +4 -2
- package/pd-cli/dist/commands/runtime-health-snapshot.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-integrity.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-integrity.js +4 -2
- package/pd-cli/dist/commands/runtime-internalization-integrity.js.map +1 -1
- package/pd-cli/dist/index.js +5 -63
- package/pd-cli/dist/index.js.map +1 -1
- package/pd-cli/dist/services/config-doctor.d.ts.map +1 -1
- package/pd-cli/dist/services/config-doctor.js +9 -2
- package/pd-cli/dist/services/config-doctor.js.map +1 -1
- package/pd-cli/dist/services/runtime-adapter-resolver.d.ts.map +1 -1
- package/pd-cli/dist/services/runtime-adapter-resolver.js +1 -0
- package/pd-cli/dist/services/runtime-adapter-resolver.js.map +1 -1
- package/plugin/dist/commands/context.js +17 -11
- package/plugin/dist/commands/samples.js +25 -0
- package/plugin/dist/core/event-log.d.ts +11 -1
- package/plugin/dist/core/event-log.js +13 -0
- package/plugin/dist/core/init.js +3 -4
- package/plugin/dist/core/rule-host.d.ts +50 -0
- package/plugin/dist/core/rule-host.js +116 -19
- package/plugin/dist/core/signal-collector-host.d.ts +105 -0
- package/plugin/dist/core/signal-collector-host.js +337 -0
- package/plugin/dist/hooks/gate.js +1 -1
- package/plugin/dist/hooks/prompt.d.ts +3 -2
- package/plugin/dist/hooks/prompt.js +48 -586
- package/plugin/dist/service/evolution-dedup.d.ts +1 -1
- package/plugin/dist/service/evolution-worker.d.ts +7 -31
- package/plugin/dist/service/evolution-worker.js +17 -36
- package/plugin/dist/service/queue-io.js +14 -2
- package/plugin/dist/service/queue-migration.d.ts +27 -26
- package/plugin/dist/service/queue-migration.js +57 -0
- package/plugin/dist/types/event-types.d.ts +1 -1
- package/plugin/dist/types.d.ts +5 -25
- package/plugin/dist/types.js +4 -9
- package/plugin/dist/utils/hashing.js +1 -1
- package/plugin/templates/langs/en/core/AGENTS.md +2 -2
- package/plugin/templates/langs/en/core/TOOLS.md +1 -1
- package/plugin/templates/langs/zh/core/AGENTS.md +2 -2
- package/plugin/templates/langs/zh/core/TOOLS.md +1 -1
- package/templates/langs/en/core/AGENTS.md +2 -2
- package/templates/langs/en/core/TOOLS.md +1 -1
- package/templates/langs/zh/core/AGENTS.md +2 -2
- package/templates/langs/zh/core/TOOLS.md +1 -1
- package/plugin/dist/constants/diagnostician.d.ts +0 -12
- package/plugin/dist/constants/diagnostician.js +0 -65
- package/plugin/dist/service/evolution-queue-migration.d.ts +0 -128
- package/plugin/dist/service/evolution-queue-migration.js +0 -53
- package/plugin/templates/langs/en/skills/pd-diagnostician/SKILL.md +0 -466
- package/plugin/templates/langs/zh/skills/pd-diagnostician/SKILL.md +0 -391
- package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +0 -287
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import { toast } from "sonner";
|
|
5
|
+
import { cn } from "../../../lib/utils.js";
|
|
6
|
+
import { enumLabel } from "../../utils/enum-labels.js";
|
|
7
|
+
import { createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, } from "../../api.js";
|
|
8
|
+
const EMPTY_FORM = {
|
|
9
|
+
id: "",
|
|
10
|
+
type: "openclaw",
|
|
11
|
+
provider: "",
|
|
12
|
+
model: "",
|
|
13
|
+
apiKeyEnv: "",
|
|
14
|
+
baseUrl: "",
|
|
15
|
+
source: "",
|
|
16
|
+
};
|
|
17
|
+
/** 状态点样式:与 AgentCard 一致 (ready=green, needs_setup/not_ready/unknown=amber, disabled=ink-4) */
|
|
18
|
+
function readinessDotClasses(readiness) {
|
|
19
|
+
const base = "w-2 h-2 rounded-full border-2 shrink-0";
|
|
20
|
+
switch (readiness) {
|
|
21
|
+
case "ready":
|
|
22
|
+
return cn(base, "border-green bg-green");
|
|
23
|
+
case "needs_setup":
|
|
24
|
+
case "not_ready":
|
|
25
|
+
case "unknown":
|
|
26
|
+
return cn(base, "border-amber bg-surface");
|
|
27
|
+
case "disabled":
|
|
28
|
+
return cn(base, "border-ink-4 bg-surface opacity-50");
|
|
29
|
+
default:
|
|
30
|
+
return cn(base, "border-ink-4 bg-surface");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build the profile object for a create request.
|
|
35
|
+
* Only includes fields relevant to the chosen type; omits empty optionals.
|
|
36
|
+
*/
|
|
37
|
+
function buildCreateProfile(form) {
|
|
38
|
+
const profile = { type: form.type };
|
|
39
|
+
if (form.type === "pi-ai") {
|
|
40
|
+
profile.provider = form.provider.trim();
|
|
41
|
+
profile.model = form.model.trim();
|
|
42
|
+
profile.apiKeyEnv = form.apiKeyEnv.trim();
|
|
43
|
+
if (form.baseUrl.trim() !== "") {
|
|
44
|
+
profile.baseUrl = form.baseUrl.trim();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
if (form.source.trim() !== "")
|
|
49
|
+
profile.source = form.source.trim();
|
|
50
|
+
if (form.provider.trim() !== "")
|
|
51
|
+
profile.provider = form.provider.trim();
|
|
52
|
+
if (form.model.trim() !== "")
|
|
53
|
+
profile.model = form.model.trim();
|
|
54
|
+
}
|
|
55
|
+
return profile;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Build the patch object for an update request.
|
|
59
|
+
* Sends `type` (server allows same-type no-op, rejects type change) plus all
|
|
60
|
+
* non-empty type-relevant fields. Empty optionals are omitted so existing
|
|
61
|
+
* values are preserved (merge-patch semantics on the server).
|
|
62
|
+
*/
|
|
63
|
+
function buildUpdatePatch(form) {
|
|
64
|
+
const patch = { type: form.type };
|
|
65
|
+
if (form.type === "pi-ai") {
|
|
66
|
+
if (form.provider.trim() !== "")
|
|
67
|
+
patch.provider = form.provider.trim();
|
|
68
|
+
if (form.model.trim() !== "")
|
|
69
|
+
patch.model = form.model.trim();
|
|
70
|
+
if (form.apiKeyEnv.trim() !== "")
|
|
71
|
+
patch.apiKeyEnv = form.apiKeyEnv.trim();
|
|
72
|
+
if (form.baseUrl.trim() !== "")
|
|
73
|
+
patch.baseUrl = form.baseUrl.trim();
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
if (form.source.trim() !== "")
|
|
77
|
+
patch.source = form.source.trim();
|
|
78
|
+
if (form.provider.trim() !== "")
|
|
79
|
+
patch.provider = form.provider.trim();
|
|
80
|
+
if (form.model.trim() !== "")
|
|
81
|
+
patch.model = form.model.trim();
|
|
82
|
+
}
|
|
83
|
+
return patch;
|
|
84
|
+
}
|
|
85
|
+
/** Pre-fill form from an existing profile summary (edit mode). */
|
|
86
|
+
function formFromProfile(p) {
|
|
87
|
+
// type is validated to be a known ProfileType by the caller before invoking;
|
|
88
|
+
// here we guard defensively without `as`.
|
|
89
|
+
const type = p.type === "pi-ai" ? "pi-ai" : "openclaw";
|
|
90
|
+
return {
|
|
91
|
+
id: p.id,
|
|
92
|
+
type,
|
|
93
|
+
provider: p.provider ?? "",
|
|
94
|
+
model: p.model ?? "",
|
|
95
|
+
apiKeyEnv: p.apiKeyEnv ?? "",
|
|
96
|
+
baseUrl: "",
|
|
97
|
+
source: "",
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export function RuntimeProfileManager({ profiles, defaultRuntimeId, onMutated, }) {
|
|
101
|
+
const { t } = useTranslation();
|
|
102
|
+
const [mode, setMode] = useState("closed");
|
|
103
|
+
const [form, setForm] = useState(EMPTY_FORM);
|
|
104
|
+
const [formError, setFormError] = useState(null);
|
|
105
|
+
const [submitting, setSubmitting] = useState(false);
|
|
106
|
+
const [deleteTarget, setDeleteTarget] = useState(null);
|
|
107
|
+
const [deleting, setDeleting] = useState(false);
|
|
108
|
+
const [deleteError, setDeleteError] = useState(null);
|
|
109
|
+
const openCreate = () => {
|
|
110
|
+
setForm(EMPTY_FORM);
|
|
111
|
+
setFormError(null);
|
|
112
|
+
setMode("create");
|
|
113
|
+
};
|
|
114
|
+
const openEdit = (p) => {
|
|
115
|
+
setForm(formFromProfile(p));
|
|
116
|
+
setFormError(null);
|
|
117
|
+
setMode("edit");
|
|
118
|
+
};
|
|
119
|
+
const closeForm = () => {
|
|
120
|
+
setMode("closed");
|
|
121
|
+
setForm(EMPTY_FORM);
|
|
122
|
+
setFormError(null);
|
|
123
|
+
};
|
|
124
|
+
const handleFieldChange = (key, value) => {
|
|
125
|
+
setForm((prev) => ({ ...prev, [key]: value }));
|
|
126
|
+
};
|
|
127
|
+
/** Validate the form; returns an error message key suffix or null if valid. */
|
|
128
|
+
function validate() {
|
|
129
|
+
if (mode === "create" && form.id.trim() === "") {
|
|
130
|
+
return t("pages.controlCenter.profiles.validationIdRequired");
|
|
131
|
+
}
|
|
132
|
+
if (form.type === "pi-ai") {
|
|
133
|
+
if (form.provider.trim() === "") {
|
|
134
|
+
return t("pages.controlCenter.profiles.validationProviderRequired");
|
|
135
|
+
}
|
|
136
|
+
if (form.model.trim() === "") {
|
|
137
|
+
return t("pages.controlCenter.profiles.validationModelRequired");
|
|
138
|
+
}
|
|
139
|
+
if (form.apiKeyEnv.trim() === "") {
|
|
140
|
+
return t("pages.controlCenter.profiles.validationApiKeyEnvRequired");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
const handleSubmit = async (e) => {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
const validationError = validate();
|
|
148
|
+
if (validationError !== null) {
|
|
149
|
+
setFormError(validationError);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
setFormError(null);
|
|
153
|
+
setSubmitting(true);
|
|
154
|
+
if (mode === "create") {
|
|
155
|
+
const result = await createRuntimeProfile(form.id.trim(), buildCreateProfile(form));
|
|
156
|
+
setSubmitting(false);
|
|
157
|
+
if (!result.success) {
|
|
158
|
+
// rc-9: surface server error (e.g. "already exists", "validation failed")
|
|
159
|
+
setFormError(result.error);
|
|
160
|
+
toast.error(t("pages.controlCenter.profiles.operationFailed"));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
toast.success(t("pages.controlCenter.profiles.createSuccess"));
|
|
164
|
+
closeForm();
|
|
165
|
+
onMutated();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// edit mode
|
|
169
|
+
const result = await updateRuntimeProfile(form.id, buildUpdatePatch(form));
|
|
170
|
+
setSubmitting(false);
|
|
171
|
+
if (!result.success) {
|
|
172
|
+
setFormError(result.error);
|
|
173
|
+
toast.error(t("pages.controlCenter.profiles.operationFailed"));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
toast.success(t("pages.controlCenter.profiles.updateSuccess"));
|
|
177
|
+
closeForm();
|
|
178
|
+
onMutated();
|
|
179
|
+
};
|
|
180
|
+
const handleDeleteConfirm = async () => {
|
|
181
|
+
if (deleteTarget === null)
|
|
182
|
+
return;
|
|
183
|
+
setDeleting(true);
|
|
184
|
+
setDeleteError(null);
|
|
185
|
+
const result = await deleteRuntimeProfile(deleteTarget);
|
|
186
|
+
setDeleting(false);
|
|
187
|
+
if (!result.success) {
|
|
188
|
+
// rc-9: surface reason (e.g. "referenced by agents: diagnostician")
|
|
189
|
+
setDeleteError(result.error);
|
|
190
|
+
toast.error(t("pages.controlCenter.profiles.operationFailed"));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
toast.success(t("pages.controlCenter.profiles.deleteSuccess"));
|
|
194
|
+
setDeleteTarget(null);
|
|
195
|
+
setDeleteError(null);
|
|
196
|
+
onMutated();
|
|
197
|
+
};
|
|
198
|
+
const handleDeleteCancel = () => {
|
|
199
|
+
setDeleteTarget(null);
|
|
200
|
+
setDeleteError(null);
|
|
201
|
+
};
|
|
202
|
+
const inputClass = "bg-surface border border-line-2 rounded-[3px] px-[10px] py-[6px] text-[12.5px] text-ink focus:outline-none focus:border-gov disabled:opacity-50 disabled:cursor-not-allowed w-full";
|
|
203
|
+
const labelClass = "block font-mono text-[10.5px] uppercase tracking-[0.04em] text-ink-4 mb-[4px]";
|
|
204
|
+
const hintClass = "mt-[3px] text-[11px] text-ink-4 leading-[1.4]";
|
|
205
|
+
return (_jsxs("div", { id: "runtime-profile-manager", className: "scroll-mt-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-[12px] mb-3", children: [_jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed", children: t("pages.controlCenter.profiles.sectionDescription") }), mode === "closed" && (_jsx("button", { type: "button", onClick: openCreate, className: "shrink-0 border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:border-line-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.controlCenter.profiles.createButton") }))] }), mode !== "closed" && (_jsxs("form", { onSubmit: handleSubmit, className: "mb-[10px] bg-panel border border-line rounded-[6px] px-[16px] py-[14px]", children: [_jsxs("div", { className: "flex items-center justify-between mb-3", children: [_jsx("h4", { className: "text-[13px] font-semibold text-ink", children: mode === "create"
|
|
206
|
+
? t("pages.controlCenter.profiles.formTitleCreate")
|
|
207
|
+
: t("pages.controlCenter.profiles.formTitleEdit", {
|
|
208
|
+
id: form.id,
|
|
209
|
+
}) }), _jsx("button", { type: "button", onClick: closeForm, className: "text-[12px] text-ink-4 hover:text-ink-2 transition-colors", children: t("pages.controlCenter.profiles.cancelButton") })] }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-[14px] gap-y-[12px]", children: [_jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-id", children: t("pages.controlCenter.profiles.fieldId") }), _jsx("input", { id: "rpf-id", type: "text", value: form.id, onChange: (e) => handleFieldChange("id", e.target.value), disabled: mode === "edit" || submitting, placeholder: t("pages.controlCenter.profiles.fieldIdPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false }), _jsx("p", { className: hintClass, children: t("pages.controlCenter.profiles.fieldIdHint") })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-type", children: t("pages.controlCenter.profiles.fieldType") }), _jsxs("select", { id: "rpf-type", value: form.type, onChange: (e) => {
|
|
210
|
+
// rc-2: no `as` bypass — narrow via runtime check.
|
|
211
|
+
// The select only emits "openclaw" | "pi-ai", but we guard
|
|
212
|
+
// defensively so the value is provably ProfileType.
|
|
213
|
+
const v = e.target.value;
|
|
214
|
+
const typed = v === "pi-ai" ? "pi-ai" : "openclaw";
|
|
215
|
+
handleFieldChange("type", typed);
|
|
216
|
+
}, disabled: mode === "edit" || submitting, className: inputClass, children: [_jsx("option", { value: "openclaw", children: t("pages.controlCenter.profiles.typeOpenclaw") }), _jsx("option", { value: "pi-ai", children: t("pages.controlCenter.profiles.typePiAi") })] }), mode === "edit" && (_jsx("p", { className: hintClass, children: t("pages.controlCenter.profiles.fieldIdHint") }))] }), form.type === "pi-ai" && (_jsxs(_Fragment, { children: [_jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-provider", children: t("pages.controlCenter.profiles.fieldProvider") }), _jsx("input", { id: "rpf-provider", type: "text", value: form.provider, onChange: (e) => handleFieldChange("provider", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldProviderPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-model", children: t("pages.controlCenter.profiles.fieldModel") }), _jsx("input", { id: "rpf-model", type: "text", value: form.model, onChange: (e) => handleFieldChange("model", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldModelPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-apikeyenv", children: t("pages.controlCenter.profiles.fieldApiKeyEnv") }), _jsx("input", { id: "rpf-apikeyenv", type: "text", value: form.apiKeyEnv, onChange: (e) => handleFieldChange("apiKeyEnv", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldApiKeyEnvPlaceholder"), className: cn(inputClass, "font-mono"), autoComplete: "off", spellCheck: false }), _jsx("p", { className: hintClass, children: t("pages.controlCenter.profiles.fieldApiKeyEnvHint") })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-baseurl", children: t("pages.controlCenter.profiles.fieldBaseUrl") }), _jsx("input", { id: "rpf-baseurl", type: "text", value: form.baseUrl, onChange: (e) => handleFieldChange("baseUrl", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldBaseUrlPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] })] })), form.type === "openclaw" && (_jsxs(_Fragment, { children: [_jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-source", children: t("pages.controlCenter.profiles.fieldSource") }), _jsx("input", { id: "rpf-source", type: "text", value: form.source, onChange: (e) => handleFieldChange("source", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldSourcePlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-provider-oc", children: t("pages.controlCenter.profiles.fieldProvider") }), _jsx("input", { id: "rpf-provider-oc", type: "text", value: form.provider, onChange: (e) => handleFieldChange("provider", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldProviderPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-model-oc", children: t("pages.controlCenter.profiles.fieldModel") }), _jsx("input", { id: "rpf-model-oc", type: "text", value: form.model, onChange: (e) => handleFieldChange("model", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldModelPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] })] }))] }), formError !== null && (_jsx("div", { className: "mt-3 px-[12px] py-[8px] border border-red/35 rounded-[4px] bg-red/10 text-[12px] text-red font-mono", children: formError })), _jsxs("div", { className: "mt-3 flex items-center gap-[8px]", children: [_jsx("button", { type: "submit", disabled: submitting, className: "border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: submitting
|
|
217
|
+
? mode === "create"
|
|
218
|
+
? t("pages.controlCenter.profiles.creating")
|
|
219
|
+
: t("pages.controlCenter.profiles.saving")
|
|
220
|
+
: t("pages.controlCenter.profiles.saveButton") }), _jsx("button", { type: "button", onClick: closeForm, disabled: submitting, className: "border border-line bg-surface text-ink-3 rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:border-line-2 hover:text-ink transition-colors disabled:opacity-50", children: t("pages.controlCenter.profiles.cancelButton") })] })] })), profiles.length === 0 ? (_jsx("div", { className: "bg-surface border border-line-2 rounded-[4px] px-[16px] py-[14px] text-[12.5px] text-ink-4 italic", children: t("pages.controlCenter.profiles.empty") })) : (_jsxs("div", { className: "bg-surface border border-line-2 rounded-[4px] overflow-hidden", children: [_jsxs("div", { className: "grid grid-cols-[12px_1fr_84px_1fr_1fr_1fr_auto] gap-[10px] items-center px-[16px] py-[9px] bg-paper-2 border-b border-line-2 font-mono text-[10.5px] uppercase tracking-[0.04em] text-ink-4", children: [_jsx("span", {}), _jsx("span", { children: t("pages.controlCenter.profiles.columnId") }), _jsx("span", { children: t("pages.controlCenter.profiles.columnType") }), _jsx("span", { children: t("pages.controlCenter.profiles.columnProvider") }), _jsx("span", { children: t("pages.controlCenter.profiles.columnModel") }), _jsx("span", { children: t("pages.controlCenter.profiles.columnApiKeyEnv") }), _jsx("span", { className: "text-right", children: t("pages.controlCenter.profiles.columnActions") })] }), profiles.map((p) => {
|
|
221
|
+
const isDefault = p.id === defaultRuntimeId;
|
|
222
|
+
const isDeleteTarget = deleteTarget === p.id;
|
|
223
|
+
return (_jsxs("div", { className: "border-b border-line-2 last:border-b-0", children: [_jsxs("div", { className: "grid grid-cols-[12px_1fr_84px_1fr_1fr_1fr_auto] gap-[10px] items-center px-[16px] py-[10px] text-[12.5px]", children: [_jsx("div", { className: readinessDotClasses(p.readiness), "aria-label": enumLabel("readiness", p.readiness, t), title: enumLabel("readiness", p.readiness, t) }), _jsxs("div", { className: "min-w-0 flex items-center gap-[6px]", children: [_jsx("span", { className: "font-mono text-[12px] text-ink truncate", children: p.id }), isDefault && (_jsx("span", { className: "shrink-0 text-[9.5px] font-mono px-[5px] py-[1px] rounded-[2px] bg-gov/10 text-gov border border-gov/22 tracking-[0.02em]", children: "default" }))] }), _jsx("span", { className: "font-mono text-[11.5px] text-ink-3", children: p.type }), _jsx("span", { className: "text-ink-3 truncate", children: p.provider ?? "—" }), _jsx("span", { className: "text-ink-3 truncate", children: p.model ?? "—" }), _jsx("span", { className: "font-mono text-[11.5px] text-ink-3 truncate", children: p.apiKeyEnv ?? "—" }), _jsxs("div", { className: "flex items-center justify-end gap-[6px]", children: [_jsx("button", { type: "button", onClick: () => openEdit(p), disabled: mode !== "closed" || deleting, className: "text-[11.5px] px-[10px] py-[4px] rounded-[3px] border border-line bg-surface text-ink-3 hover:border-line-2 hover:text-ink transition-colors disabled:opacity-40 disabled:cursor-not-allowed", children: t("pages.controlCenter.profiles.editButton") }), _jsx("button", { type: "button", onClick: () => {
|
|
224
|
+
setDeleteTarget(p.id);
|
|
225
|
+
setDeleteError(null);
|
|
226
|
+
}, disabled: mode !== "closed" ||
|
|
227
|
+
deleting ||
|
|
228
|
+
deleteTarget !== null, className: "text-[11.5px] px-[10px] py-[4px] rounded-[3px] border border-line bg-surface text-ink-3 hover:border-red/40 hover:text-red transition-colors disabled:opacity-40 disabled:cursor-not-allowed", children: t("pages.controlCenter.profiles.deleteButton") })] })] }), isDeleteTarget && (_jsx("div", { className: "px-[16px] pb-[12px]", children: _jsxs("div", { className: "px-[12px] py-[10px] border border-danger rounded-[4px] bg-danger/10 text-[12px] text-ink-2 leading-[1.55]", children: [_jsx("div", { className: "font-medium", children: t("pages.controlCenter.profiles.deleteConfirmMessage", {
|
|
229
|
+
id: p.id,
|
|
230
|
+
}) }), isDefault && (_jsx("div", { className: "mt-1 text-ink-3", children: t("pages.controlCenter.profiles.sectionDescription") })), deleteError !== null && (_jsx("div", { className: "mt-2 font-mono text-[11.5px] text-red", children: deleteError })), _jsxs("div", { className: "mt-2 flex gap-[8px]", children: [_jsx("button", { type: "button", onClick: handleDeleteConfirm, disabled: deleting, className: "text-[11.5px] px-[12px] py-[4px] rounded-[3px] border border-transparent bg-danger text-paper font-medium hover:opacity-90 transition-opacity disabled:opacity-50 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: deleting
|
|
231
|
+
? t("pages.controlCenter.profiles.deleting")
|
|
232
|
+
: t("pages.controlCenter.profiles.deleteConfirmAck") }), _jsx("button", { type: "button", onClick: handleDeleteCancel, disabled: deleting, className: "text-[11.5px] px-[12px] py-[4px] rounded-[3px] border border-line bg-transparent text-ink-3 hover:border-line-2 transition-colors disabled:opacity-50", children: t("pages.controlCenter.profiles.deleteConfirmCancel") })] })] }) }))] }, p.id));
|
|
233
|
+
})] }))] }));
|
|
234
|
+
}
|
|
@@ -49,7 +49,7 @@ function DebtCard({ item, onArchive, onDeactivate, isProcessing, }) {
|
|
|
49
49
|
const isStagnant = item.type === "stagnant";
|
|
50
50
|
return (_jsx("article", { className: "p-5 bg-panel border border-line rounded-[6px] hover:border-line-2 transition-colors relative", "aria-label": t("pages.debt.principleAriaLabel", { id: item.id }), children: _jsxs("div", { className: "flex flex-col md:flex-row md:items-start gap-4", children: [_jsxs("div", { className: "flex-1 space-y-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-mono text-[11px] uppercase px-2 py-0.5 bg-line rounded text-ink-3", children: item.id }), _jsx("span", { className: `font-mono text-[11px] uppercase px-2 py-0.5 rounded ${isStagnant
|
|
51
51
|
? "bg-amber/10 text-amber"
|
|
52
|
-
: "bg-danger/10 text-danger"}`, children: isStagnant ? t("pages.focus.summaryStagnation") : t("pages.sidebar.debt") })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-ink text-[15px] font-medium leading-relaxed", children: item.text }), item.triggerPattern && (_jsxs("p", { className: "text-ink-3 text-[13px] font-mono leading-relaxed", children: [t("principles.detail.triggerLabel", { defaultValue: "Trigger:" }), " ", item.triggerPattern] }))] }), _jsxs("div", { className: "flex items-start gap-2 pt-1", children: [_jsx(AlertTriangle, { className: "w-4 h-4 text-amber shrink-0 mt-0.5", "aria-hidden": "true" }), _jsxs("div", { className: "text-[13px] leading-relaxed", children: [_jsxs("span", { className: "font-semibold text-ink-3", children: [t("pages.debt.suggestedAction"), ": "] }), renderReason()] })] })] }), _jsx("div", { className: "flex flex-col gap-2 shrink-0 md:w-48", children: !confirmAction ? (_jsxs(_Fragment, { children: [_jsxs("button", { onClick: handleArchiveClick, disabled: isProcessing, className: "w-full inline-flex items-center justify-center gap-1.5 border border-line bg-surface text-ink hover:border-line-2 transition-colors rounded-[3px] px-[14px] py-[6px] text-[12.5px] focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `archive-btn-${item.id}`, children: [_jsx(Archive, { className: "w-4 h-4 text-ink-3", "aria-hidden": "true" }), t("pages.debt.actionArchive")] }), item.activeActivationRecords && item.activeActivationRecords.length > 0 ? (item.activeActivationRecords.map((ar) => (_jsxs("button", { onClick: () => handleDeactivateClick(ar.
|
|
52
|
+
: "bg-danger/10 text-danger"}`, children: isStagnant ? t("pages.focus.summaryStagnation") : t("pages.sidebar.debt") })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-ink text-[15px] font-medium leading-relaxed", children: item.text }), item.triggerPattern && (_jsxs("p", { className: "text-ink-3 text-[13px] font-mono leading-relaxed", children: [t("principles.detail.triggerLabel", { defaultValue: "Trigger:" }), " ", item.triggerPattern] }))] }), _jsxs("div", { className: "flex items-start gap-2 pt-1", children: [_jsx(AlertTriangle, { className: "w-4 h-4 text-amber shrink-0 mt-0.5", "aria-hidden": "true" }), _jsxs("div", { className: "text-[13px] leading-relaxed", children: [_jsxs("span", { className: "font-semibold text-ink-3", children: [t("pages.debt.suggestedAction"), ": "] }), renderReason()] })] })] }), _jsx("div", { className: "flex flex-col gap-2 shrink-0 md:w-48", children: !confirmAction ? (_jsxs(_Fragment, { children: [_jsxs("button", { onClick: handleArchiveClick, disabled: isProcessing, className: "w-full inline-flex items-center justify-center gap-1.5 border border-line bg-surface text-ink hover:border-line-2 transition-colors rounded-[3px] px-[14px] py-[6px] text-[12.5px] focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `archive-btn-${item.id}`, children: [_jsx(Archive, { className: "w-4 h-4 text-ink-3", "aria-hidden": "true" }), t("pages.debt.actionArchive")] }), item.activeActivationRecords && item.activeActivationRecords.length > 0 ? (item.activeActivationRecords.map((ar) => (_jsxs("button", { onClick: () => handleDeactivateClick(ar.activationId), disabled: isProcessing, className: "w-full inline-flex items-center justify-center gap-1.5 border border-danger/20 bg-surface text-danger hover:bg-danger/5 transition-colors rounded-[3px] px-[14px] py-[6px] text-[12.5px] focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `deactivate-btn-${ar.activationId}`, children: [_jsx(Trash2, { className: "w-4 h-4 text-danger/80", "aria-hidden": "true" }), t("pages.debt.actionDeactivate"), " (", ar.channel, ")"] }, ar.activationId)))) : (_jsx("button", { disabled: true, className: "w-full inline-flex items-center justify-center gap-1.5 border border-line bg-surface/50 text-ink-4 cursor-not-allowed rounded-[3px] px-[14px] py-[6px] text-[12.5px]", title: t("pages.debt.demoteTooltip"), children: t("pages.debt.actionKeep") }))] })) : (_jsxs("div", { className: "flex flex-col gap-2 p-3 bg-surface border border-amber/20 rounded-[4px] w-full", role: "alert", "data-testid": `confirm-bar-${item.id}`, children: [_jsx("p", { className: "text-ink-2 text-[12px] leading-relaxed", children: confirmAction === "archive"
|
|
53
53
|
? t("pages.debt.confirmArchive")
|
|
54
54
|
: t("pages.debt.confirmDeactivate") }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: "default", size: "sm", onClick: handleConfirm, disabled: isProcessing, className: "flex-1 text-[12px] py-1", "data-testid": `confirm-btn-${item.id}`, children: t("common.confirm") }), _jsx(Button, { variant: "outline", size: "sm", onClick: handleCancel, className: "flex-1 text-[12px] py-1", children: t("common.cancel") })] })] })) })] }) }));
|
|
55
55
|
}
|
|
@@ -189,7 +189,7 @@ export function DebtPage() {
|
|
|
189
189
|
.map((item) => {
|
|
190
190
|
if (item.id !== principleId)
|
|
191
191
|
return item;
|
|
192
|
-
const updatedActivations = item.activeActivationRecords?.filter((ar) => ar.
|
|
192
|
+
const updatedActivations = item.activeActivationRecords?.filter((ar) => ar.activationId !== activationId);
|
|
193
193
|
return {
|
|
194
194
|
...item,
|
|
195
195
|
activeActivationRecords: updatedActivations,
|
|
@@ -7,7 +7,8 @@ import { cn } from "../../../lib/utils.js";
|
|
|
7
7
|
import { PageShell } from "../../components/layout/page-shell.js";
|
|
8
8
|
import { PageLoading } from "../../components/layout/page-loading.js";
|
|
9
9
|
import { SectionTitle } from "../../components/layout/section-title.js";
|
|
10
|
-
import { getToken, setToken, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchOutputLanguage, updateOutputLanguage, } from "../../api.js";
|
|
10
|
+
import { getToken, setToken, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchOutputLanguage, updateOutputLanguage, fetchConfigSummary, patchFeatureFlag, } from "../../api.js";
|
|
11
|
+
import { resetOnboardingState } from "../../utils/onboarding-state.js";
|
|
11
12
|
// ── Runtime validators (H section / ERR-001/005/009/013) ─────────────────────
|
|
12
13
|
/** Type guard: is this a non-null object with own properties (not inherited)? */
|
|
13
14
|
function isRecord(value) {
|
|
@@ -86,6 +87,9 @@ export function SettingsPage() {
|
|
|
86
87
|
const [addPath, setAddPath] = useState("");
|
|
87
88
|
// PRI-332: Principle output language state
|
|
88
89
|
const [outputLanguage, setOutputLanguage] = useState("zh-CN");
|
|
90
|
+
// spec 2026-06-30 §12.5: new_user_onboarding feature flag toggle state.
|
|
91
|
+
// null = loading/unknown (button disabled); true/false = persisted state.
|
|
92
|
+
const [onboardingFlagEnabled, setOnboardingFlagEnabled] = useState(null);
|
|
89
93
|
// Inline confirm for remove (J.1 pattern)
|
|
90
94
|
const [confirmRemove, setConfirmRemove] = useState(null);
|
|
91
95
|
// ── Load data on mount ──────────────────────────────────────────────────
|
|
@@ -123,14 +127,34 @@ export function SettingsPage() {
|
|
|
123
127
|
useEffect(() => {
|
|
124
128
|
loadData();
|
|
125
129
|
}, [loadData]);
|
|
130
|
+
// spec 2026-06-30 §12.5: load new_user_onboarding flag state from config summary.
|
|
131
|
+
// Non-blocking — failures keep the toggle disabled (null) and surface a toast
|
|
132
|
+
// (rc-9: no silent fallback). The flag list comes from GET /api/v1/config/summary
|
|
133
|
+
// because there is no dedicated GET /features list endpoint.
|
|
134
|
+
const loadOnboardingFlag = useCallback(async () => {
|
|
135
|
+
setOnboardingFlagEnabled(null);
|
|
136
|
+
const result = await fetchConfigSummary();
|
|
137
|
+
if (!result.success || !result.data) {
|
|
138
|
+
toast.error(t("components.onboardingFlag.loadFailed"));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const flag = result.data.features.find((f) => f.id === "new_user_onboarding");
|
|
142
|
+
if (!flag) {
|
|
143
|
+
toast.error(t("components.onboardingFlag.loadFailed"));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
setOnboardingFlagEnabled(flag.enabled);
|
|
147
|
+
}, [t]);
|
|
148
|
+
useEffect(() => { void loadOnboardingFlag(); }, [loadOnboardingFlag]);
|
|
126
149
|
// ── Auth token handlers ────────────────────────────────────────────────
|
|
127
|
-
const handleSaveToken = useCallback(() => {
|
|
150
|
+
const handleSaveToken = useCallback(async () => {
|
|
128
151
|
const trimmed = tokenInput.trim();
|
|
129
152
|
if (trimmed.length === 0)
|
|
130
153
|
return;
|
|
131
154
|
setToken(trimmed);
|
|
155
|
+
await loadOnboardingFlag();
|
|
132
156
|
toast.success(t("pages.settings.tokenSaved"));
|
|
133
|
-
}, [tokenInput, t]);
|
|
157
|
+
}, [tokenInput, loadOnboardingFlag, t]);
|
|
134
158
|
// ── Workspace handlers ─────────────────────────────────────────────────
|
|
135
159
|
const handleAddWorkspace = useCallback(async () => {
|
|
136
160
|
const name = addName.trim();
|
|
@@ -191,6 +215,41 @@ export function SettingsPage() {
|
|
|
191
215
|
}
|
|
192
216
|
toast.success(t("pages.settings.languageSaved"));
|
|
193
217
|
}, [t]);
|
|
218
|
+
// ── Onboarding flag toggle handler (spec 2026-06-30 §12.5) ────────────
|
|
219
|
+
// Calls the validated PATCH /api/v1/config/features/new_user_onboarding
|
|
220
|
+
// wrapper (patchFeatureFlag). Response is runtime-validated by validateFeatureFlagUpdate
|
|
221
|
+
// (rc-1/rc-3) before state is updated.
|
|
222
|
+
const handleToggleOnboardingFlag = useCallback(async () => {
|
|
223
|
+
if (onboardingFlagEnabled === null)
|
|
224
|
+
return;
|
|
225
|
+
const newEnabled = !onboardingFlagEnabled;
|
|
226
|
+
const result = await patchFeatureFlag("new_user_onboarding", newEnabled);
|
|
227
|
+
if (!result.success || !result.data) {
|
|
228
|
+
// rc-9: surface reason via toast instead of silent rollback
|
|
229
|
+
toast.error(t("components.onboardingFlag.toggleFailed"));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
setOnboardingFlagEnabled(result.data.enabled);
|
|
233
|
+
toast.success(t(newEnabled
|
|
234
|
+
? "components.onboardingFlag.enabled"
|
|
235
|
+
: "components.onboardingFlag.disabled"));
|
|
236
|
+
}, [onboardingFlagEnabled, t]);
|
|
237
|
+
// ── Onboarding reset handler ───────────────────────────────────────────
|
|
238
|
+
// Mirror App.tsx currentWorkspaceId derivation (App.tsx default="default",
|
|
239
|
+
// then workspaces[0].name after fetch). Using the same key ensures
|
|
240
|
+
// resetOnboardingState targets the same localStorage entry the onboarding
|
|
241
|
+
// wizard wrote — avoids a silent no-op reset (EP-09 test-reality gap).
|
|
242
|
+
const currentWorkspaceId = workspaces[0]?.name ?? "default";
|
|
243
|
+
const handleResetOnboarding = useCallback(() => {
|
|
244
|
+
const confirmed = window.confirm(t("components.onboardingReset.resetConfirm"));
|
|
245
|
+
if (confirmed) {
|
|
246
|
+
if (!resetOnboardingState(currentWorkspaceId)) {
|
|
247
|
+
toast.error(t("components.onboardingReset.resetFailed"));
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
toast.success(t("components.onboardingReset.resetSuccess"));
|
|
251
|
+
}
|
|
252
|
+
}, [currentWorkspaceId, t]);
|
|
194
253
|
// ── Loading state ────────────────────────────────────────────────────────
|
|
195
254
|
if (loadingState === "loading") {
|
|
196
255
|
return (_jsx(PageShell, { children: _jsx(PageLoading, { cardCount: 3, label: t("common.loading") }) }));
|
|
@@ -200,7 +259,7 @@ export function SettingsPage() {
|
|
|
200
259
|
return (_jsxs(PageShell, { children: [_jsx("div", { className: "font-mono text-[12px] tracking-[0.14em] text-ink-3 uppercase mb-3", children: t("pages.settings.eyebrow") }), _jsx("h1", { className: "text-[29px] font-semibold tracking-tight text-ink mb-2", children: t("pages.settings.title") }), _jsxs("div", { className: "mt-6 p-4 bg-panel border border-line rounded-[6px] text-ink-2 text-sm", children: [_jsx("p", { children: t("pages.settings.loadError") }), errorMessage && (_jsx("p", { className: "mt-2 text-ink-4 text-[13px] font-mono", children: errorMessage }))] })] }));
|
|
201
260
|
}
|
|
202
261
|
// ── Loaded state ─────────────────────────────────────────────────────────
|
|
203
|
-
return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsx("div", { className: "font-mono text-[12px] tracking-[0.14em] text-ink-3 uppercase mb-3", children: t("pages.settings.eyebrow") }), _jsx("h1", { className: "text-[29px] font-semibold tracking-tight text-ink mb-2", children: t("pages.settings.title") }), _jsx("p", { className: "text-ink-3 text-[14px] max-w-[760px] leading-relaxed mb-7", children: t("pages.settings.subtitle") }), _jsxs("section", { className: "mb-8", "aria-labelledby": "section-auth", children: [_jsx(SectionTitle, { id: "section-auth", children: t("pages.settings.auth") }), _jsxs("div", { className: "bg-panel border border-line rounded-[6px] p-5", children: [_jsx("label", { htmlFor: "bearer-token-input", className: "block text-sm font-medium text-ink mb-2", children: t("pages.settings.bearerToken") }), _jsx("input", { id: "bearer-token-input", type: "password", value: tokenInput, onChange: (e) => setTokenInput(e.target.value), placeholder: t("pages.settings.enterAccessToken"), className: "w-full border border-line bg-surface rounded-[3px] px-3 py-2 text-sm text-ink focus:outline-none focus:border-gov focus:ring-1 focus:ring-gov" }), _jsxs("div", { className: "flex items-center justify-between mt-3", children: [_jsx("button", { onClick: handleSaveToken, disabled: tokenInput.trim().length === 0, className: "border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("common.save") }), _jsx("span", { className: "text-ink-4 text-[12px]", children: t("pages.settings.tokenSessionOnly") })] })] })] }), _jsxs("section", { className: "mb-8", "aria-labelledby": "section-principle-language", children: [_jsx(SectionTitle, { id: "section-principle-language", children: t("pages.settings.principleLanguage") }), _jsxs("div", { className: "bg-panel border border-line rounded-[6px] p-5", children: [_jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed mb-3", children: t("pages.settings.principleLanguageDescription") }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("label", { htmlFor: "output-language-select", className: "text-sm font-medium text-ink", children: [t("pages.settings.principleLanguage"), ":"] }), _jsxs("select", { id: "output-language-select", value: outputLanguage, onChange: (e) => handleOutputLanguageChange(e.target.value), className: "border border-line bg-surface rounded-[3px] px-3 py-2 text-sm text-ink focus:outline-none focus:border-gov focus:ring-1 focus:ring-gov", children: [_jsx("option", { value: "zh-CN", children: t("pages.settings.languageZhCN") }), _jsx("option", { value: "en", children: t("pages.settings.languageEn") })] })] })] })] }), _jsxs("section", { className: "mb-8", "aria-labelledby": "section-sound-alerts", children: [_jsx(SectionTitle, { id: "section-sound-alerts", children: t("pages.settings.notifications") }), _jsx("div", { className: "bg-panel border border-line rounded-[6px] p-5", children: _jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: "sound-alerts-toggle", className: "block text-sm font-medium text-ink", children: t("pages.settings.soundAlerts") }), _jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed mt-1", children: t("pages.settings.soundAlertsDescription") })] }), _jsx("button", { id: "sound-alerts-toggle", type: "button", role: "switch", "aria-checked": soundEnabled, onClick: () => setSoundEnabled(!soundEnabled), className: cn("relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", soundEnabled ? "bg-gov" : "bg-line"), children: _jsx("span", { className: cn("inline-block h-4 w-4 transform rounded-full bg-paper transition-transform", soundEnabled ? "translate-x-6" : "translate-x-1") }) })] }) })] }), _jsxs("section", { "aria-labelledby": "section-workspaces", children: [_jsx(SectionTitle, { id: "section-workspaces", children: t("pages.settings.workspace") }), workspaces.length > 0 ? (_jsx("div", { className: "space-y-[10px] mb-5", children: workspaces.map((ws) => (_jsx("article", { className: "bg-panel border border-line rounded-[6px] p-5", children: _jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "font-medium text-ink text-sm", children: ws.name }), _jsx("div", { className: "text-ink-3 text-[13px] mt-1 font-mono break-all", children: ws.path }), _jsxs("div", { className: "text-ink-4 text-[12px] mt-1", children: [t("pages.settings.lastSync"), ":", " ", ws.lastSync ?? "—"] })] }), _jsx("div", { className: "flex items-center gap-2 shrink-0", children: confirmRemove?.workspaceName === ws.name ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-ink-2 text-[12px]", children: t("pages.settings.confirmDeleteDescription", {
|
|
262
|
+
return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsx("div", { className: "font-mono text-[12px] tracking-[0.14em] text-ink-3 uppercase mb-3", children: t("pages.settings.eyebrow") }), _jsx("h1", { className: "text-[29px] font-semibold tracking-tight text-ink mb-2", children: t("pages.settings.title") }), _jsx("p", { className: "text-ink-3 text-[14px] max-w-[760px] leading-relaxed mb-7", children: t("pages.settings.subtitle") }), _jsxs("section", { className: "mb-8", "aria-labelledby": "section-auth", children: [_jsx(SectionTitle, { id: "section-auth", children: t("pages.settings.auth") }), _jsxs("div", { className: "bg-panel border border-line rounded-[6px] p-5", children: [_jsx("label", { htmlFor: "bearer-token-input", className: "block text-sm font-medium text-ink mb-2", children: t("pages.settings.bearerToken") }), _jsx("input", { id: "bearer-token-input", type: "password", value: tokenInput, onChange: (e) => setTokenInput(e.target.value), placeholder: t("pages.settings.enterAccessToken"), className: "w-full border border-line bg-surface rounded-[3px] px-3 py-2 text-sm text-ink focus:outline-none focus:border-gov focus:ring-1 focus:ring-gov" }), _jsxs("div", { className: "flex items-center justify-between mt-3", children: [_jsx("button", { onClick: handleSaveToken, disabled: tokenInput.trim().length === 0, className: "border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("common.save") }), _jsx("span", { className: "text-ink-4 text-[12px]", children: t("pages.settings.tokenSessionOnly") })] })] })] }), _jsxs("section", { className: "mb-8", "aria-labelledby": "section-principle-language", children: [_jsx(SectionTitle, { id: "section-principle-language", children: t("pages.settings.principleLanguage") }), _jsxs("div", { className: "bg-panel border border-line rounded-[6px] p-5", children: [_jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed mb-3", children: t("pages.settings.principleLanguageDescription") }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("label", { htmlFor: "output-language-select", className: "text-sm font-medium text-ink", children: [t("pages.settings.principleLanguage"), ":"] }), _jsxs("select", { id: "output-language-select", value: outputLanguage, onChange: (e) => handleOutputLanguageChange(e.target.value), className: "border border-line bg-surface rounded-[3px] px-3 py-2 text-sm text-ink focus:outline-none focus:border-gov focus:ring-1 focus:ring-gov", children: [_jsx("option", { value: "zh-CN", children: t("pages.settings.languageZhCN") }), _jsx("option", { value: "en", children: t("pages.settings.languageEn") })] })] })] })] }), _jsxs("section", { className: "mb-8", "aria-labelledby": "section-sound-alerts", children: [_jsx(SectionTitle, { id: "section-sound-alerts", children: t("pages.settings.notifications") }), _jsx("div", { className: "bg-panel border border-line rounded-[6px] p-5", children: _jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: "sound-alerts-toggle", className: "block text-sm font-medium text-ink", children: t("pages.settings.soundAlerts") }), _jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed mt-1", children: t("pages.settings.soundAlertsDescription") })] }), _jsx("button", { id: "sound-alerts-toggle", type: "button", role: "switch", "aria-checked": soundEnabled, onClick: () => setSoundEnabled(!soundEnabled), className: cn("relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", soundEnabled ? "bg-gov" : "bg-line"), children: _jsx("span", { className: cn("inline-block h-4 w-4 transform rounded-full bg-paper transition-transform", soundEnabled ? "translate-x-6" : "translate-x-1") }) })] }) })] }), _jsxs("section", { className: "mb-8", "aria-labelledby": "section-workspaces", children: [_jsx(SectionTitle, { id: "section-workspaces", children: t("pages.settings.workspace") }), workspaces.length > 0 ? (_jsx("div", { className: "space-y-[10px] mb-5", children: workspaces.map((ws) => (_jsx("article", { className: "bg-panel border border-line rounded-[6px] p-5", children: _jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "font-medium text-ink text-sm", children: ws.name }), _jsx("div", { className: "text-ink-3 text-[13px] mt-1 font-mono break-all", children: ws.path }), _jsxs("div", { className: "text-ink-4 text-[12px] mt-1", children: [t("pages.settings.lastSync"), ":", " ", ws.lastSync ?? "—"] })] }), _jsx("div", { className: "flex items-center gap-2 shrink-0", children: confirmRemove?.workspaceName === ws.name ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-ink-2 text-[12px]", children: t("pages.settings.confirmDeleteDescription", {
|
|
204
263
|
name: ws.name,
|
|
205
|
-
}) }), _jsx("button", { onClick: () => handleRemoveWorkspace(ws.name), className: "border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("common.confirm") }), _jsx("button", { onClick: () => setConfirmRemove(null), className: "border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("common.cancel") })] })) : (_jsxs(_Fragment, { children: [_jsx("button", { onClick: () => handleSyncWorkspace(ws.name), className: "border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.settings.syncWorkspace") }), _jsx("button", { onClick: () => setConfirmRemove({ workspaceName: ws.name }), className: "border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.settings.removeWorkspace") })] })) })] }) }, ws.name))) })) : (_jsx("div", { className: "text-ink-3 text-[13px] leading-relaxed py-3 mb-5", children: "\u2014" })), _jsx("div", { className: "bg-panel border border-line rounded-[6px] p-5", children: _jsxs("div", { className: "flex items-end gap-3", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("label", { htmlFor: "add-workspace-name", className: "block text-sm font-medium text-ink mb-2", children: t("pages.settings.name") }), _jsx("input", { id: "add-workspace-name", type: "text", value: addName, onChange: (e) => setAddName(e.target.value), placeholder: t("pages.settings.addNamePlaceholder"), className: "w-full border border-line bg-surface rounded-[3px] px-3 py-2 text-sm text-ink focus:outline-none focus:border-gov focus:ring-1 focus:ring-gov" })] }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("label", { htmlFor: "add-workspace-path", className: "block text-sm font-medium text-ink mb-2", children: t("pages.settings.path") }), _jsx("input", { id: "add-workspace-path", type: "text", value: addPath, onChange: (e) => setAddPath(e.target.value), placeholder: t("pages.settings.addPathPlaceholder"), className: "w-full border border-line bg-surface rounded-[3px] px-3 py-2 text-sm text-ink focus:outline-none focus:border-gov focus:ring-1 focus:ring-gov" })] }), _jsx("button", { onClick: handleAddWorkspace, disabled: addName.trim().length === 0 || addPath.trim().length === 0, className: "border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed shrink-0 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.settings.addWorkspace") })] }) })] })] }) }));
|
|
264
|
+
}) }), _jsx("button", { onClick: () => handleRemoveWorkspace(ws.name), className: "border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("common.confirm") }), _jsx("button", { onClick: () => setConfirmRemove(null), className: "border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("common.cancel") })] })) : (_jsxs(_Fragment, { children: [_jsx("button", { onClick: () => handleSyncWorkspace(ws.name), className: "border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.settings.syncWorkspace") }), _jsx("button", { onClick: () => setConfirmRemove({ workspaceName: ws.name }), className: "border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.settings.removeWorkspace") })] })) })] }) }, ws.name))) })) : (_jsx("div", { className: "text-ink-3 text-[13px] leading-relaxed py-3 mb-5", children: "\u2014" })), _jsx("div", { className: "bg-panel border border-line rounded-[6px] p-5", children: _jsxs("div", { className: "flex items-end gap-3", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("label", { htmlFor: "add-workspace-name", className: "block text-sm font-medium text-ink mb-2", children: t("pages.settings.name") }), _jsx("input", { id: "add-workspace-name", type: "text", value: addName, onChange: (e) => setAddName(e.target.value), placeholder: t("pages.settings.addNamePlaceholder"), className: "w-full border border-line bg-surface rounded-[3px] px-3 py-2 text-sm text-ink focus:outline-none focus:border-gov focus:ring-1 focus:ring-gov" })] }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("label", { htmlFor: "add-workspace-path", className: "block text-sm font-medium text-ink mb-2", children: t("pages.settings.path") }), _jsx("input", { id: "add-workspace-path", type: "text", value: addPath, onChange: (e) => setAddPath(e.target.value), placeholder: t("pages.settings.addPathPlaceholder"), className: "w-full border border-line bg-surface rounded-[3px] px-3 py-2 text-sm text-ink focus:outline-none focus:border-gov focus:ring-1 focus:ring-gov" })] }), _jsx("button", { onClick: handleAddWorkspace, disabled: addName.trim().length === 0 || addPath.trim().length === 0, className: "border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed shrink-0 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.settings.addWorkspace") })] }) })] }), _jsxs("section", { className: "mb-8", "aria-labelledby": "section-onboarding-flag", children: [_jsx(SectionTitle, { id: "section-onboarding-flag", children: t("components.onboardingFlag.title") }), _jsx("div", { className: "bg-panel border border-line rounded-[6px] p-5", children: _jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("label", { htmlFor: "onboarding-flag-toggle", className: "block text-sm font-medium text-ink", children: t("components.onboardingFlag.label") }), _jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed mt-1", children: t("components.onboardingFlag.description") })] }), _jsx("button", { id: "onboarding-flag-toggle", type: "button", role: "switch", "aria-checked": onboardingFlagEnabled ?? false, "aria-label": t("components.onboardingFlag.toggleAriaLabel"), onClick: handleToggleOnboardingFlag, disabled: onboardingFlagEnabled === null, className: cn("relative inline-flex h-6 w-11 shrink-0 items-center rounded-full transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2 disabled:opacity-50 disabled:cursor-not-allowed", onboardingFlagEnabled ? "bg-gov" : "bg-line"), children: _jsx("span", { className: cn("inline-block h-4 w-4 transform rounded-full bg-paper transition-transform", onboardingFlagEnabled ? "translate-x-6" : "translate-x-1") }) })] }) })] }), _jsxs("section", { "aria-labelledby": "section-onboarding-reset", children: [_jsx(SectionTitle, { id: "section-onboarding-reset", children: t("components.onboardingReset.title") }), _jsx("div", { className: "bg-panel border border-line rounded-[6px] p-5", children: _jsx("button", { onClick: handleResetOnboarding, className: "border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("components.onboardingReset.resetButton") }) })] })] }) }));
|
|
206
265
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { KeywordCategory } from "../../utils/signal-keywords-types.js";
|
|
2
|
+
interface KeywordEditDialogProps {
|
|
3
|
+
/** Phase 2: 提交新关键词 */
|
|
4
|
+
onSubmit?: (data: {
|
|
5
|
+
term: string;
|
|
6
|
+
category: KeywordCategory;
|
|
7
|
+
precision: "high" | "ambiguous";
|
|
8
|
+
weight: number;
|
|
9
|
+
}) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function KeywordEditDialog({ onSubmit }: KeywordEditDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import { Plus } from "lucide-react";
|
|
5
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogClose, } from "../../components/ui/dialog.js";
|
|
6
|
+
import { Button } from "../../components/ui/button.js";
|
|
7
|
+
import { Tooltip, TooltipContent, TooltipTrigger, } from "../../components/ui/tooltip.js";
|
|
8
|
+
// ── Constants ───────────────────────────────────────────────────────────────
|
|
9
|
+
// ── Component ───────────────────────────────────────────────────────────────
|
|
10
|
+
export function KeywordEditDialog({ onSubmit }) {
|
|
11
|
+
const { t } = useTranslation();
|
|
12
|
+
const [open, setOpen] = useState(false);
|
|
13
|
+
const [term, setTerm] = useState("");
|
|
14
|
+
const [category, setCategory] = useState("correction");
|
|
15
|
+
const [precision, setPrecision] = useState("high");
|
|
16
|
+
const [weight, setWeight] = useState(0.8);
|
|
17
|
+
const handleSubmit = () => {
|
|
18
|
+
if (!onSubmit)
|
|
19
|
+
return;
|
|
20
|
+
if (!term.trim())
|
|
21
|
+
return;
|
|
22
|
+
onSubmit({ term: term.trim(), category, precision, weight });
|
|
23
|
+
setTerm("");
|
|
24
|
+
setCategory("correction");
|
|
25
|
+
setPrecision("high");
|
|
26
|
+
setWeight(0.8);
|
|
27
|
+
setOpen(false);
|
|
28
|
+
};
|
|
29
|
+
const isDisabled = !onSubmit;
|
|
30
|
+
return (_jsxs(Dialog, { open: open, onOpenChange: setOpen, children: [isDisabled ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { children: _jsxs(Button, { disabled: true, variant: "default", size: "sm", children: [_jsx(Plus, { className: "h-4 w-4 mr-1" }), t("pages.signalKeywords.addKeyword")] }) }) }), _jsx(TooltipContent, { children: t("pages.signalKeywords.phase2Tooltip") })] })) : (_jsx(DialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "default", size: "sm", children: [_jsx(Plus, { className: "h-4 w-4 mr-1" }), t("pages.signalKeywords.addKeyword")] }) })), _jsxs(DialogContent, { className: "sm:max-w-[420px]", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { className: "text-[15px] font-semibold text-ink", children: t("pages.signalKeywords.addKeywordDialogTitle") }) }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-[12px] font-medium text-ink-3", children: t("pages.signalKeywords.colTerm") }), _jsx("input", { type: "text", value: term, onChange: (e) => setTerm(e.target.value), placeholder: t("pages.signalKeywords.searchPlaceholder"), disabled: isDisabled, className: "w-full h-9 px-3 text-[13px] bg-surface border border-line rounded-[4px] text-ink placeholder:text-ink-4 outline-none focus:border-gov transition-colors disabled:opacity-40 disabled:cursor-not-allowed" })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-[12px] font-medium text-ink-3", children: t("pages.signalKeywords.colCategory") }), _jsxs("select", { value: category, onChange: (e) => {
|
|
31
|
+
const v = e.target.value;
|
|
32
|
+
if (v === "correction" || v === "empathy") {
|
|
33
|
+
setCategory(v);
|
|
34
|
+
}
|
|
35
|
+
}, disabled: isDisabled, className: "w-full h-9 px-3 text-[13px] bg-surface border border-line rounded-[4px] text-ink outline-none focus:border-gov transition-colors disabled:opacity-40 disabled:cursor-not-allowed", children: [_jsx("option", { value: "correction", children: t("pages.signalKeywords.categoryCorrection") }), _jsx("option", { value: "empathy", children: t("pages.signalKeywords.categoryEmpathy") })] })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-[12px] font-medium text-ink-3", children: t("pages.signalKeywords.colPrecision") }), _jsxs("select", { value: precision, onChange: (e) => {
|
|
36
|
+
const v = e.target.value;
|
|
37
|
+
if (v === "high" || v === "ambiguous") {
|
|
38
|
+
setPrecision(v);
|
|
39
|
+
}
|
|
40
|
+
}, disabled: isDisabled, className: "w-full h-9 px-3 text-[13px] bg-surface border border-line rounded-[4px] text-ink outline-none focus:border-gov transition-colors disabled:opacity-40 disabled:cursor-not-allowed", children: [_jsx("option", { value: "high", children: t("pages.signalKeywords.precisionHigh") }), _jsx("option", { value: "ambiguous", children: t("pages.signalKeywords.precisionAmbiguous") })] })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-[12px] font-medium text-ink-3", children: t("pages.signalKeywords.weightLabel", { percent: Math.round(weight * 100) }) }), _jsx("input", { type: "range", min: "0", max: "1", step: "0.05", value: weight, onChange: (e) => setWeight(parseFloat(e.target.value)), disabled: isDisabled, className: "w-full h-1.5 bg-surface rounded-full appearance-none cursor-pointer accent-gov disabled:opacity-40 disabled:cursor-not-allowed [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3.5 [&::-webkit-slider-thumb]:h-3.5 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-gov [&::-webkit-slider-thumb]:shadow-sm" }), _jsxs("div", { className: "flex justify-between text-[10px] text-ink-4", children: [_jsx("span", { children: "0%" }), _jsx("span", { children: "50%" }), _jsx("span", { children: "100%" })] })] })] }), _jsxs("div", { className: "flex items-center justify-end gap-2 mt-2", children: [_jsx(DialogClose, { asChild: true, children: _jsx(Button, { variant: "outline", size: "sm", children: t("pages.signalKeywords.confirmDeleteCancel") }) }), _jsx(Button, { variant: "default", size: "sm", onClick: handleSubmit, disabled: isDisabled || !term.trim(), children: t("pages.signalKeywords.submitAdd") })] })] })] }));
|
|
41
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type SignalKeyword } from "../../api.js";
|
|
2
|
+
interface KeywordListSectionProps {
|
|
3
|
+
keywords: SignalKeyword[];
|
|
4
|
+
/** Phase 2: 删除关键词的回调 */
|
|
5
|
+
onDelete?: (term: string) => void;
|
|
6
|
+
/** Phase 2: 归档/恢复关键词的回调 */
|
|
7
|
+
onToggleArchive?: (term: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function KeywordListSection({ keywords, onDelete, onToggleArchive, }: KeywordListSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useMemo } from "react";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import { Search, Trash2, Archive } from "lucide-react";
|
|
5
|
+
import { Badge } from "../../components/ui/badge.js";
|
|
6
|
+
import { Tooltip, TooltipContent, TooltipTrigger, } from "../../components/ui/tooltip.js";
|
|
7
|
+
// ── Component ───────────────────────────────────────────────────────────────
|
|
8
|
+
export function KeywordListSection({ keywords, onDelete, onToggleArchive, }) {
|
|
9
|
+
const { t } = useTranslation();
|
|
10
|
+
// 搜索文本
|
|
11
|
+
const [search, setSearch] = useState("");
|
|
12
|
+
// 筛选标签
|
|
13
|
+
const [filterTab, setFilterTab] = useState("all");
|
|
14
|
+
// 过滤后的关键词列表
|
|
15
|
+
const filtered = useMemo(() => {
|
|
16
|
+
let list = keywords;
|
|
17
|
+
// 按 filter tab 过滤
|
|
18
|
+
// Phase 1: 无 archived 状态,暂不过滤
|
|
19
|
+
// Phase 2: 添加对 archived 状态的过滤
|
|
20
|
+
void filterTab;
|
|
21
|
+
// 按 search 文本过滤
|
|
22
|
+
if (search.trim()) {
|
|
23
|
+
const q = search.trim().toLowerCase();
|
|
24
|
+
list = list.filter((kw) => kw.term.toLowerCase().includes(q));
|
|
25
|
+
}
|
|
26
|
+
return list;
|
|
27
|
+
}, [keywords, search, filterTab]);
|
|
28
|
+
// 分类中文映射
|
|
29
|
+
const categoryLabel = {
|
|
30
|
+
correction: t("pages.signalKeywords.categoryCorrection"),
|
|
31
|
+
empathy: t("pages.signalKeywords.categoryEmpathy"),
|
|
32
|
+
};
|
|
33
|
+
const hasWriteOps = !!onDelete || !!onToggleArchive;
|
|
34
|
+
return (_jsxs("section", { children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsx("h2", { className: "text-[15px] font-semibold text-ink", children: t("pages.signalKeywords.title") }), _jsxs("span", { className: "text-[12px] text-ink-4 tabular-nums", children: [filtered.length, " / ", keywords.length] })] }), _jsxs("div", { className: "flex items-center gap-3 mb-4", children: [_jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-ink-4" }), _jsx("input", { type: "text", value: search, onChange: (e) => setSearch(e.target.value), placeholder: t("pages.signalKeywords.searchPlaceholder"), className: "w-full h-9 pl-9 pr-3 text-[13px] bg-surface border border-line rounded-[4px] text-ink placeholder:text-ink-4 outline-none focus:border-gov transition-colors" })] }), _jsx("div", { className: "flex items-center gap-1 p-0.5 bg-surface border border-line rounded-[4px]", children: ["all", "active"].map((tab) => (_jsx("button", { type: "button", onClick: () => setFilterTab(tab), className: `px-3 py-1.5 text-[12px] font-medium rounded-[3px] transition-colors ${filterTab === tab
|
|
35
|
+
? "bg-gov/10 text-gov"
|
|
36
|
+
: "text-ink-4 hover:text-ink"}`, children: t(`pages.signalKeywords.filter${tab.charAt(0).toUpperCase() + tab.slice(1)}`) }, tab))) })] }), filtered.length === 0 ? (_jsx("div", { className: "px-4 py-12 text-center text-[13px] text-ink-4 border border-dashed border-line-2 rounded-[4px]", children: search.trim()
|
|
37
|
+
? t("pages.signalKeywords.noSearchResults")
|
|
38
|
+
: t("pages.signalKeywords.empty") })) : (_jsxs("div", { className: "border border-line rounded-[4px] overflow-hidden", children: [_jsxs("div", { className: "grid grid-cols-[1fr_100px_90px_90px_80px] gap-3 px-4 py-2.5 bg-surface text-[11px] font-medium text-ink-4 uppercase tracking-[var(--tracking-wide)] border-b border-line", children: [_jsx("span", { children: t("pages.signalKeywords.colTerm") }), _jsx("span", { children: t("pages.signalKeywords.colCategory") }), _jsx("span", { children: t("pages.signalKeywords.colPrecision") }), _jsx("span", { children: t("pages.signalKeywords.colWeight") }), hasWriteOps && _jsx("span", { className: "text-right", children: t("pages.signalKeywords.colActions") })] }), filtered.map((kw) => (_jsxs("div", { className: "grid grid-cols-[1fr_100px_90px_90px_80px] gap-3 px-4 py-3 items-center border-b border-line last:border-b-0 hover:bg-surface/50 transition-colors", children: [_jsx("span", { className: "text-[13px] text-ink font-medium truncate", children: kw.term }), _jsx(Badge, { variant: kw.category === "correction" ? "default" : "amber", children: categoryLabel[kw.category] ?? kw.category }), _jsx("span", { className: "text-[12px] text-ink-3", children: kw.precision === "high" ? (_jsx("span", { className: "text-green", children: t("pages.signalKeywords.precisionHigh") })) : (_jsx("span", { className: "text-amber", children: t("pages.signalKeywords.precisionAmbiguous") })) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex-1 h-1.5 bg-surface rounded-full overflow-hidden", children: _jsx("div", { className: "h-full rounded-full bg-gov/60 transition-all", style: { width: `${kw.weight * 100}%` } }) }), _jsxs("span", { className: "text-[11px] text-ink-4 tabular-nums w-8 text-right", children: [Math.round(kw.weight * 100), "%"] })] }), hasWriteOps && (_jsxs("div", { className: "flex items-center justify-end gap-1", children: [onToggleArchive && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => onToggleArchive(kw.term), disabled: true, className: "p-1.5 text-ink-4 hover:text-ink disabled:opacity-30 disabled:cursor-not-allowed transition-colors", "aria-label": t("pages.signalKeywords.archiveSuccess"), children: _jsx(Archive, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: t("pages.signalKeywords.phase2Tooltip") })] })), onDelete && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => onDelete(kw.term), disabled: true, className: "p-1.5 text-ink-4 hover:text-danger disabled:opacity-30 disabled:cursor-not-allowed transition-colors", "aria-label": t("pages.signalKeywords.confirmDeleteTitle"), children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: t("pages.signalKeywords.phase2Tooltip") })] }))] }))] }, kw.term)))] }))] }));
|
|
39
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type PendingSignalTerm } from "../../api.js";
|
|
2
|
+
interface PendingTermsSectionProps {
|
|
3
|
+
terms: PendingSignalTerm[];
|
|
4
|
+
/** Phase 2: 确认一个 pending term */
|
|
5
|
+
onConfirm?: (term: PendingSignalTerm) => void;
|
|
6
|
+
/** Phase 2: 忽略一个 pending term */
|
|
7
|
+
onIgnore?: (term: string) => void;
|
|
8
|
+
/** Phase 2: 批量确认 */
|
|
9
|
+
onConfirmAll?: () => void;
|
|
10
|
+
/** Phase 2: 批量忽略 */
|
|
11
|
+
onIgnoreAll?: () => void;
|
|
12
|
+
}
|
|
13
|
+
export declare function PendingTermsSection({ terms, onConfirm, onIgnore, onConfirmAll, onIgnoreAll, }: PendingTermsSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export {};
|