create-principles-disciple 1.100.0 → 1.102.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/index.js +9 -0
- package/console/dist/server/models/ActivationsConsoleModel.d.ts +37 -1
- package/console/dist/server/models/ActivationsConsoleModel.js +114 -13
- 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 +17 -1
- package/console/dist/ui/api.js +6 -1
- 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 +15 -0
- package/console/dist/ui/i18n/en.json +127 -0
- package/console/dist/ui/i18n/zh-CN.json +127 -0
- package/console/dist/ui/pages/activation/ActivationValidators.js +1 -1
- package/console/dist/ui/pages/control-center/AgentCard.js +10 -3
- package/console/dist/ui/pages/control-center/ControlCenterPage.js +1 -1
- 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/web/assets/app.css +401 -0
- package/console/dist/web/assets/app.js +6904 -1835
- 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__/admission-gate.test.js +63 -1
- package/core/dist/runtime-v2/__tests__/admission-gate.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +21 -5
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/chain-integrity-attack.test.js +17 -0
- package/core/dist/runtime-v2/__tests__/chain-integrity-attack.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/chain-integrity-real-path.test.js +12 -0
- package/core/dist/runtime-v2/__tests__/chain-integrity-real-path.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__/internalization-chain-integrity-read-model.test.js +168 -1
- package/core/dist/runtime-v2/__tests__/internalization-chain-integrity-read-model.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/activation/__tests__/activation-dispatcher.test.js +53 -0
- package/core/dist/runtime-v2/activation/__tests__/activation-dispatcher.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/__tests__/helpers.d.ts +21 -0
- package/core/dist/runtime-v2/activation/__tests__/helpers.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/helpers.js +132 -0
- package/core/dist/runtime-v2/activation/__tests__/helpers.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/story-a-acceptance.test.js +2 -117
- package/core/dist/runtime-v2/activation/__tests__/story-a-acceptance.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/activation-dispatcher.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/activation-dispatcher.js +18 -2
- package/core/dist/runtime-v2/activation/activation-dispatcher.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 +253 -6
- 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 +96 -2
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.js.map +1 -1
- package/core/dist/runtime-v2/admission-gate.d.ts +27 -0
- package/core/dist/runtime-v2/admission-gate.d.ts.map +1 -1
- package/core/dist/runtime-v2/admission-gate.js +55 -0
- package/core/dist/runtime-v2/admission-gate.js.map +1 -1
- package/core/dist/runtime-v2/cli/diagnose.d.ts +4 -0
- package/core/dist/runtime-v2/cli/diagnose.d.ts.map +1 -1
- package/core/dist/runtime-v2/cli/diagnose.js +25 -0
- package/core/dist/runtime-v2/cli/diagnose.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 +7 -0
- 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 +28 -0
- 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 +1 -0
- 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-defaults.d.ts +2 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.js +12 -0
- 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-feature-flags.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-feature-flags.js +6 -1
- package/core/dist/runtime-v2/config/pd-config-feature-flags.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 +9 -0
- package/core/dist/runtime-v2/config/pd-config-redaction.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-types.d.ts +110 -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 +114 -1
- 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/__tests__/plugin-surface-registry.test.js +12 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/plugin-surface-registry.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/feature-flags/plugin-surface-registry.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js +8 -2
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +6 -4
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +5 -3
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder-v2.test.js +25 -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 +21 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-runner.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.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-distiller-runner.js +4 -1
- package/core/dist/runtime-v2/internalization/diag-distiller-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.js +7 -1
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-router-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-router-runner.js +4 -1
- 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 +7 -0
- package/core/dist/runtime-v2/internalization/internalization-task-guards.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-task-guards.js +8 -0
- package/core/dist/runtime-v2/internalization/internalization-task-guards.js.map +1 -1
- package/core/dist/runtime-v2/internalization-chain-integrity-read-model.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization-chain-integrity-read-model.js +57 -1
- package/core/dist/runtime-v2/internalization-chain-integrity-read-model.js.map +1 -1
- package/core/dist/runtime-v2/proven-channel-baseline.js +1 -1
- package/core/dist/runtime-v2/proven-channel-baseline.js.map +1 -1
- package/core/dist/runtime-v2/runner/__tests__/diagnose.test.js +91 -1
- package/core/dist/runtime-v2/runner/__tests__/diagnose.test.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/candidate/sqlite-candidate-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/candidate/sqlite-candidate-store.js +19 -0
- package/core/dist/runtime-v2/store/candidate/sqlite-candidate-store.js.map +1 -1
- package/core/dist/runtime-v2/store/schema-conformance.test.js +73 -0
- package/core/dist/runtime-v2/store/schema-conformance.test.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection-schema-version.test.js +41 -7
- package/core/dist/runtime-v2/store/sqlite-connection-schema-version.test.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.js +22 -1
- package/core/dist/runtime-v2/store/sqlite-connection.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 +167 -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 +12 -2
- package/dist/mvp-config.js.map +1 -1
- package/package.json +1 -1
- package/pd-cli/dist/commands/candidate.d.ts.map +1 -1
- package/pd-cli/dist/commands/candidate.js +89 -7
- package/pd-cli/dist/commands/candidate.js.map +1 -1
- package/pd-cli/dist/commands/pain-retry.d.ts +3 -0
- package/pd-cli/dist/commands/pain-retry.d.ts.map +1 -1
- package/pd-cli/dist/commands/pain-retry.js +39 -14
- package/pd-cli/dist/commands/pain-retry.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 +244 -10
- package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
- package/pd-cli/dist/index.js +7 -84
- package/pd-cli/dist/index.js.map +1 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.js +1 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.js.map +1 -1
- package/pd-cli/package.json +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 +68 -0
- package/plugin/dist/core/rule-host.js +167 -28
- 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/prompt.d.ts +3 -2
- package/plugin/dist/hooks/prompt.js +47 -571
- 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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
|
+
import { useNavigate } from "react-router-dom";
|
|
4
5
|
import { ChevronRight } from "lucide-react";
|
|
5
6
|
import { cn } from "../../../lib/utils.js";
|
|
6
7
|
/** 状态点样式:ready / notready / off */
|
|
@@ -68,6 +69,7 @@ function renderTextWithCode(text) {
|
|
|
68
69
|
}
|
|
69
70
|
export function AgentCard({ agent, meta, profiles, onBindingChange, saving, locale, }) {
|
|
70
71
|
const { t } = useTranslation();
|
|
72
|
+
const navigate = useNavigate();
|
|
71
73
|
const isSaving = saving === agent.name;
|
|
72
74
|
// L2 / L3 / confirm 状态
|
|
73
75
|
const [isOpen, setIsOpen] = useState(false);
|
|
@@ -81,14 +83,16 @@ export function AgentCard({ agent, meta, profiles, onBindingChange, saving, loca
|
|
|
81
83
|
const impact = isZh ? meta.impactZh : meta.impactEn;
|
|
82
84
|
const techDetail = isZh ? meta.techDetailZh : meta.techDetailEn;
|
|
83
85
|
const mvpNote = isZh ? meta.mvpNoteZh : meta.mvpNoteEn;
|
|
86
|
+
const actionLinkText = isZh ? meta.action?.linkTextZh : meta.action?.linkTextEn;
|
|
84
87
|
// 段落用 \n\n 分隔
|
|
85
88
|
const detailParagraphs = detail.split("\n\n").filter((p) => p.length > 0);
|
|
86
|
-
// 头部点击:toggle isOpen(但点击 toggle 按钮 / confirm-bar / tech-toggle 不触发)
|
|
89
|
+
// 头部点击:toggle isOpen(但点击 toggle 按钮 / confirm-bar / tech-toggle / action-row 不触发)
|
|
87
90
|
const handleHeadClick = (e) => {
|
|
88
91
|
const target = e.target;
|
|
89
92
|
if (target.closest("[data-agent-toggle]") ||
|
|
90
93
|
target.closest("[data-confirm-bar]") ||
|
|
91
|
-
target.closest("[data-tech-toggle]")
|
|
94
|
+
target.closest("[data-tech-toggle]") ||
|
|
95
|
+
target.closest("[data-action-row]")) {
|
|
92
96
|
return;
|
|
93
97
|
}
|
|
94
98
|
setIsOpen((prev) => !prev);
|
|
@@ -146,7 +150,10 @@ export function AgentCard({ agent, meta, profiles, onBindingChange, saving, loca
|
|
|
146
150
|
? t("pages.controlCenter.saving")
|
|
147
151
|
: agent.enabled
|
|
148
152
|
? t("pages.controlCenter.on")
|
|
149
|
-
: t("pages.controlCenter.off") }), _jsx(ChevronRight, { className: cn("w-[14px] h-[14px] text-ink-4 transition-transform shrink-0", isOpen && "rotate-90"), "aria-hidden": "true" })] }), isOpen && (_jsxs("div", { className: "px-[16px] pb-[14px] border-t border-line-2 bg-panel", children: [_jsx("div", { className: "pt-[14px] text-[13px] text-ink-3 leading-[1.62]", children: detailParagraphs.map((para, i) => (_jsx("p", { className: i > 0 ? "mt-2" : undefined, children: renderTextWithCode(para) }, i))) }), mvpNote && (_jsx("div", { className: "mt-3 text-[12px] text-ink-4 font-mono italic", children: mvpNote })), _jsxs("div", { className: cn("mt-[12px] px-[12px] py-[10px] border border-line-2 border-l-[2.5px] rounded-[4px] bg-paper-2 text-[12.5px] text-ink-3 leading-[1.55]", impactBorderClass(meta.impactLevel)), children: [_jsx("span", { className: cn("block mb-[3px] text-[10px] font-mono uppercase tracking-[0.08em] font-medium", impactLabelClass(meta.impactLevel)), children: t("pages.controlCenter.impact.label") }), impact] }),
|
|
153
|
+
: t("pages.controlCenter.off") }), _jsx(ChevronRight, { className: cn("w-[14px] h-[14px] text-ink-4 transition-transform shrink-0", isOpen && "rotate-90"), "aria-hidden": "true" })] }), isOpen && (_jsxs("div", { className: "px-[16px] pb-[14px] border-t border-line-2 bg-panel", children: [_jsx("div", { className: "pt-[14px] text-[13px] text-ink-3 leading-[1.62]", children: detailParagraphs.map((para, i) => (_jsx("p", { className: i > 0 ? "mt-2" : undefined, children: renderTextWithCode(para) }, i))) }), mvpNote && (_jsx("div", { className: "mt-3 text-[12px] text-ink-4 font-mono italic", children: mvpNote })), _jsxs("div", { className: cn("mt-[12px] px-[12px] py-[10px] border border-line-2 border-l-[2.5px] rounded-[4px] bg-paper-2 text-[12.5px] text-ink-3 leading-[1.55]", impactBorderClass(meta.impactLevel)), children: [_jsx("span", { className: cn("block mb-[3px] text-[10px] font-mono uppercase tracking-[0.08em] font-medium", impactLabelClass(meta.impactLevel)), children: t("pages.controlCenter.impact.label") }), impact] }), meta.action && actionLinkText && (_jsx("div", { "data-action-row": true, className: "mt-[12px] pt-[12px] border-t border-line-2", children: _jsxs("button", { type: "button", onClick: (e) => {
|
|
154
|
+
e.stopPropagation();
|
|
155
|
+
navigate(meta.action.to);
|
|
156
|
+
}, className: "flex items-center gap-[6px] text-[12px] text-gov hover:text-gov-2 transition-colors font-medium", children: [_jsx("span", { children: actionLinkText }), _jsx(ChevronRight, { className: "w-[12px] h-[12px]", "aria-hidden": "true" })] }) })), Object.keys(techDetail).length > 0 && (_jsxs(_Fragment, { children: [_jsxs("div", { "data-tech-toggle": true, className: "mt-[12px] pt-[12px] border-t border-line-2 flex items-center gap-[6px] cursor-pointer text-[11px] text-ink-4 font-mono uppercase tracking-[0.04em] hover:text-ink-2 transition-colors", onClick: handleTechToggleClick, role: "button", tabIndex: 0, "aria-expanded": showTechDetail, onKeyDown: (e) => {
|
|
150
157
|
if (e.key === "Enter" || e.key === " ") {
|
|
151
158
|
e.preventDefault();
|
|
152
159
|
e.stopPropagation();
|
|
@@ -503,7 +503,7 @@ export function ControlCenterPage() {
|
|
|
503
503
|
const locale = i18n.language.startsWith("en")
|
|
504
504
|
? "en"
|
|
505
505
|
: "zh-CN";
|
|
506
|
-
return (_jsxs(_Fragment, { children: [AGENT_GROUPS.map((groupMeta) => (_jsx(AgentGroup, { groupMeta: groupMeta, agents: groups[groupMeta.id], profiles: availableProfiles, onBindingChange: handleBindingChange, saving: savingAgent, locale: locale }, groupMeta.id))), unknown.length > 0 && (_jsx("div", { className: "mt-3 px-3 py-2 border border-amber/30 border-l-2 border-l-amber rounded-[4px] bg-amber/10 text-[12.5px] text-ink-3", children: t("pages.controlCenter.unknownAgentsWarning", {
|
|
506
|
+
return (_jsxs(_Fragment, { children: [AGENT_GROUPS.map((groupMeta) => (_jsx(AgentGroup, { groupMeta: groupMeta, agents: (groups[groupMeta.id] ?? []).filter((a) => a.name !== AGENT_METADATA.signalCollector.name), profiles: availableProfiles, onBindingChange: handleBindingChange, saving: savingAgent, locale: locale }, groupMeta.id))), unknown.length > 0 && (_jsx("div", { className: "mt-3 px-3 py-2 border border-amber/30 border-l-2 border-l-amber rounded-[4px] bg-amber/10 text-[12.5px] text-ink-3", children: t("pages.controlCenter.unknownAgentsWarning", {
|
|
507
507
|
count: unknown.length,
|
|
508
508
|
names: unknown.map((a) => a.name).join(", "),
|
|
509
509
|
}) }))] }));
|
|
@@ -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 {};
|
|
@@ -0,0 +1,35 @@
|
|
|
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 { Check, X, CheckCheck, XCircle } from "lucide-react";
|
|
5
|
+
import { Badge } from "../../components/ui/badge.js";
|
|
6
|
+
import { Tooltip, TooltipContent, TooltipTrigger, } from "../../components/ui/tooltip.js";
|
|
7
|
+
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
8
|
+
// ── Component ───────────────────────────────────────────────────────────────
|
|
9
|
+
export function PendingTermsSection({ terms, onConfirm, onIgnore, onConfirmAll, onIgnoreAll, }) {
|
|
10
|
+
const { t, i18n } = useTranslation();
|
|
11
|
+
const [selected, setSelected] = useState(new Set());
|
|
12
|
+
const hasBatchOps = !!onConfirmAll || !!onIgnoreAll;
|
|
13
|
+
const hasRowOps = !!onConfirm || !!onIgnore;
|
|
14
|
+
// 分类中文映射
|
|
15
|
+
const categoryLabel = {
|
|
16
|
+
correction: t("pages.signalKeywords.categoryCorrection"),
|
|
17
|
+
empathy: t("pages.signalKeywords.categoryEmpathy"),
|
|
18
|
+
};
|
|
19
|
+
// 切换选中
|
|
20
|
+
const toggleSelected = (term) => {
|
|
21
|
+
setSelected((prev) => {
|
|
22
|
+
const next = new Set(prev);
|
|
23
|
+
if (next.has(term)) {
|
|
24
|
+
next.delete(term);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
next.add(term);
|
|
28
|
+
}
|
|
29
|
+
return next;
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
return (_jsxs("section", { children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-[15px] font-semibold text-ink", children: t("pages.signalKeywords.pendingTerms.title") }), _jsx("p", { className: "mt-0.5 text-[12px] text-ink-4 leading-[1.5]", children: t("pages.signalKeywords.pendingTerms.subtitle") })] }), _jsx("span", { className: "text-[12px] text-ink-4 tabular-nums", children: t("pages.signalKeywords.nTerms", { count: terms.length }) })] }), terms.length > 0 && hasBatchOps && (_jsxs("div", { className: "flex items-center justify-between mb-3 px-3 py-2 bg-surface border border-line rounded-[4px]", children: [_jsx("span", { className: "text-[12px] text-ink-4", children: selected.size > 0
|
|
33
|
+
? t("pages.signalKeywords.selectedNOfTotal", { selected: selected.size, total: terms.length })
|
|
34
|
+
: t("pages.signalKeywords.nTermsPendingReview", { count: terms.length }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", onClick: () => onConfirmAll?.(), disabled: true, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-[12px] font-medium text-green bg-green/10 rounded-[3px] disabled:opacity-30 disabled:cursor-not-allowed hover:bg-green/20 transition-colors", children: [_jsx(CheckCheck, { className: "h-3.5 w-3.5" }), t("pages.signalKeywords.pendingTerms.confirmBatch")] }) }), _jsx(TooltipContent, { children: t("pages.signalKeywords.phase2Tooltip") })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", onClick: () => onIgnoreAll?.(), disabled: true, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-[12px] font-medium text-ink-4 bg-surface border border-line rounded-[3px] disabled:opacity-30 disabled:cursor-not-allowed hover:text-danger hover:border-danger/30 transition-colors", children: [_jsx(XCircle, { className: "h-3.5 w-3.5" }), t("pages.signalKeywords.pendingTerms.ignoreBatch")] }) }), _jsx(TooltipContent, { children: t("pages.signalKeywords.phase2Tooltip") })] })] })] })), terms.length === 0 ? (_jsxs("div", { className: "px-4 py-12 text-center text-[13px] text-ink-4 border border-dashed border-line-2 rounded-[4px]", children: [_jsx("p", { children: t("pages.signalKeywords.pendingTerms.empty") }), _jsx("p", { className: "mt-2 text-[12px]", children: t("pages.signalKeywords.pendingTerms.emptyDescription") })] })) : (_jsxs("div", { className: "border border-line rounded-[4px] overflow-hidden", children: [_jsxs("div", { className: "grid grid-cols-[24px_1fr_100px_90px_1fr_100px] 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 items-center", children: [_jsx("span", {}), _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.colReason") }), hasRowOps && _jsx("span", { className: "text-right", children: t("pages.signalKeywords.colActions") })] }), terms.map((term) => (_jsxs("div", { className: "grid grid-cols-[24px_1fr_100px_90px_1fr_100px] gap-3 px-4 py-3 items-start border-b border-line last:border-b-0 hover:bg-surface/50 transition-colors", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("input", { type: "checkbox", checked: selected.has(term.term), onChange: () => toggleSelected(term.term), disabled: true, className: "mt-0.5 h-3.5 w-3.5 rounded border-line text-gov disabled:opacity-30 disabled:cursor-not-allowed" }) }), _jsx(TooltipContent, { children: t("pages.signalKeywords.phase2Tooltip") })] }), _jsxs("div", { className: "min-w-0", children: [_jsx("span", { className: "text-[13px] text-ink font-medium block truncate", children: term.term }), _jsx("span", { className: "text-[11px] text-ink-4 mt-0.5 block", children: new Date(term.discoveredAt).toLocaleDateString(i18n.language) })] }), _jsx(Badge, { variant: term.suggestedCategory === "correction" ? "default" : "amber", children: categoryLabel[term.suggestedCategory] ?? term.suggestedCategory }), _jsx("span", { className: "text-[12px] text-ink-3", children: term.suggestedPrecision === "high" ? (_jsx("span", { className: "text-green", children: t("pages.signalKeywords.precisionHigh") })) : (_jsx("span", { className: "text-amber", children: t("pages.signalKeywords.precisionAmbiguous") })) }), _jsx("span", { className: "text-[12px] text-ink-3 leading-[1.5] line-clamp-2", children: term.reason }), hasRowOps && (_jsxs("div", { className: "flex items-center justify-end gap-1", children: [onConfirm && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => onConfirm(term), disabled: true, className: "p-1.5 text-ink-4 hover:text-green disabled:opacity-30 disabled:cursor-not-allowed transition-colors", "aria-label": t("pages.signalKeywords.pendingTerms.confirm"), children: _jsx(Check, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: t("pages.signalKeywords.phase2Tooltip") })] })), onIgnore && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => onIgnore(term.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.pendingTerms.ignore"), children: _jsx(X, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: t("pages.signalKeywords.phase2Tooltip") })] }))] }))] }, term.term)))] }))] }));
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function SignalKeywordsPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useCallback } from "react";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import { useNavigate } from "react-router-dom";
|
|
5
|
+
import { ArrowLeft } from "lucide-react";
|
|
6
|
+
import { listActiveSignalKeywords, listPendingSignalTerms, } from "../../api.js";
|
|
7
|
+
import { KeywordListSection } from "./KeywordListSection.js";
|
|
8
|
+
import { PendingTermsSection } from "./PendingTermsSection.js";
|
|
9
|
+
import { KeywordEditDialog } from "./KeywordEditDialog.js";
|
|
10
|
+
export function SignalKeywordsPage() {
|
|
11
|
+
const { t } = useTranslation();
|
|
12
|
+
const navigate = useNavigate();
|
|
13
|
+
const [keywords, setKeywords] = useState([]);
|
|
14
|
+
const [pendingTerms, setPendingTerms] = useState([]);
|
|
15
|
+
const [loading, setLoading] = useState(true);
|
|
16
|
+
const [error, setError] = useState(null);
|
|
17
|
+
const loadData = useCallback(async () => {
|
|
18
|
+
setLoading(true);
|
|
19
|
+
setError(null);
|
|
20
|
+
try {
|
|
21
|
+
const [kwResult, ptResult] = await Promise.all([
|
|
22
|
+
listActiveSignalKeywords(),
|
|
23
|
+
listPendingSignalTerms(),
|
|
24
|
+
]);
|
|
25
|
+
if (!kwResult.success) {
|
|
26
|
+
setError(t("pages.signalKeywords.loadError"));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (!ptResult.success) {
|
|
30
|
+
setError(t("pages.signalKeywords.loadError"));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
setKeywords(kwResult.data ?? []);
|
|
34
|
+
setPendingTerms(ptResult.data ?? []);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
setError(t("pages.signalKeywords.loadError"));
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
setLoading(false);
|
|
41
|
+
}
|
|
42
|
+
}, [t]);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
loadData();
|
|
45
|
+
}, [loadData]);
|
|
46
|
+
return (_jsxs("div", { className: "max-w-[960px] mx-auto px-6 py-8", children: [_jsxs("div", { className: "flex items-center gap-3 mb-6", children: [_jsxs("button", { type: "button", onClick: () => navigate("/control-center"), className: "flex items-center gap-1.5 text-[13px] text-ink-3 hover:text-ink transition-colors", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), t("pages.controlCenter.eyebrow")] }), _jsx("span", { className: "text-ink-4 text-[13px]", children: "/" }), _jsx("span", { className: "text-[13px] text-ink font-medium", children: t("pages.signalKeywords.title") })] }), error && (_jsx("div", { className: "mb-6 px-4 py-3 border border-danger rounded-[4px] bg-danger/10 text-[13px] text-danger", children: error })), loading && (_jsx("div", { className: "flex items-center justify-center py-20", children: _jsx("div", { className: "w-6 h-6 border-2 border-gov border-t-transparent rounded-full animate-spin" }) })), !loading && !error && (_jsxs("div", { className: "space-y-8", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-[20px] font-semibold text-ink tracking-[-0.01em]", children: t("pages.signalKeywords.title") }), _jsx("p", { className: "mt-1 text-[13px] text-ink-3 leading-[1.55]", children: t("pages.signalKeywords.subtitle") })] }), _jsx(KeywordListSection, { keywords: keywords }), _jsx(PendingTermsSection, { terms: pendingTerms }), _jsx("div", { className: "pt-2 border-t border-line", children: _jsx(KeywordEditDialog
|
|
47
|
+
// Phase 2: onSubmit
|
|
48
|
+
, {}) })] }))] }));
|
|
49
|
+
}
|