@1agh/maude 0.42.0 → 0.44.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/apps/studio/.ai/cache/_stats.json +7 -0
- package/apps/studio/acp/bootstrap-brief.ts +12 -2
- package/apps/studio/acp/bridge.ts +44 -10
- package/apps/studio/acp/env.ts +23 -0
- package/apps/studio/acp/login-state.ts +263 -0
- package/apps/studio/acp/plugin-bootstrap.ts +31 -25
- package/apps/studio/acp/probe.ts +152 -1
- package/apps/studio/annotations-layer.tsx +1451 -324
- package/apps/studio/annotations-model.ts +58 -0
- package/apps/studio/api.ts +568 -24
- package/apps/studio/bin/_audio-search.mjs +140 -0
- package/apps/studio/bin/_import-asset-pdf-worker.mjs +34 -0
- package/apps/studio/bin/_import-asset.mjs +815 -0
- package/apps/studio/bin/_import-brand.mjs +635 -0
- package/apps/studio/bin/_import-tokens-alias-resolver.mjs +95 -0
- package/apps/studio/bin/_import-tokens.mjs +1201 -0
- package/apps/studio/bin/_ingest-footage.mjs +386 -0
- package/apps/studio/bin/_probe-footage-playwright.mjs +269 -0
- package/apps/studio/bin/_transcribe.mjs +419 -0
- package/apps/studio/bin/_transcribe.test.mjs +80 -0
- package/apps/studio/bin/_video-playwright.mjs +141 -71
- package/apps/studio/bin/audio-search.sh +28 -0
- package/apps/studio/bin/generate.sh +154 -0
- package/apps/studio/bin/import-asset.sh +34 -0
- package/apps/studio/bin/import-brand.sh +29 -0
- package/apps/studio/bin/import-tokens.sh +33 -0
- package/apps/studio/bin/ingest-footage.sh +27 -0
- package/apps/studio/bin/photo-adjust.sh +163 -0
- package/apps/studio/bin/photo-bg-remove.sh +258 -0
- package/apps/studio/bin/probe-footage.sh +28 -0
- package/apps/studio/bin/read-annotations.mjs +125 -2
- package/apps/studio/bin/transcribe.sh +39 -0
- package/apps/studio/canvas-edit.ts +656 -12
- package/apps/studio/canvas-lib.tsx +637 -10
- package/apps/studio/canvas-pipeline.ts +65 -7
- package/apps/studio/canvas-shell.tsx +156 -16
- package/apps/studio/client/app.jsx +2385 -699
- package/apps/studio/client/export-center.jsx +35 -1
- package/apps/studio/client/generate-dialog.jsx +352 -0
- package/apps/studio/client/github.js +18 -0
- package/apps/studio/client/inspector-controls.jsx +781 -0
- package/apps/studio/client/panels/BrandUploadPanel.jsx +233 -0
- package/apps/studio/client/panels/ChatPanel.jsx +15 -33
- package/apps/studio/client/panels/GitPanel.jsx +8 -0
- package/apps/studio/client/panels/IntroVideoDialog.jsx +44 -0
- package/apps/studio/client/panels/OnboardingWizard.jsx +12 -0
- package/apps/studio/client/panels/ReadinessList.jsx +227 -7
- package/apps/studio/client/panels/RepoBranchSwitcher.jsx +133 -21
- package/apps/studio/client/panels/SettingsPanel.jsx +828 -0
- package/apps/studio/client/panels/SetupChecklist.jsx +223 -0
- package/apps/studio/client/panels/StickerPicker.jsx +160 -0
- package/apps/studio/client/panels/TimelinePanel.jsx +15 -2
- package/apps/studio/client/photo-knobs.jsx +432 -0
- package/apps/studio/client/styles/3-shell-maude.css +376 -28
- package/apps/studio/client/styles/4-components.css +223 -0
- package/apps/studio/client/styles/6-acp-chat.css +86 -0
- package/apps/studio/client/tour/quick-setup-tour.js +39 -0
- package/apps/studio/commands/annotation-strokes-command.ts +13 -3
- package/apps/studio/commands/edit-source-command.ts +31 -4
- package/apps/studio/config.schema.json +70 -0
- package/apps/studio/context-menu.tsx +42 -8
- package/apps/studio/context.ts +16 -0
- package/apps/studio/design-setup-readiness.ts +115 -0
- package/apps/studio/dist/client.bundle.js +5572 -21
- package/apps/studio/dist/comment-mount.js +2 -2
- package/apps/studio/dist/runtime/.min-sizes.json +1 -0
- package/apps/studio/dist/runtime/@imgly_background-removal.js +5543 -0
- package/apps/studio/dist/runtime/pixi-js.js +519 -519
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/dom-selection.ts +25 -0
- package/apps/studio/draw/palette.ts +34 -0
- package/apps/studio/exporters/jobs.ts +47 -5
- package/apps/studio/exporters/video.ts +24 -4
- package/apps/studio/footage/schema.test.ts +287 -0
- package/apps/studio/footage/schema.ts +662 -0
- package/apps/studio/footage-store.ts +235 -0
- package/apps/studio/fs-watch.ts +10 -0
- package/apps/studio/generation/adapters/elevenlabs.ts +370 -0
- package/apps/studio/generation/adapters/gemini.ts +542 -0
- package/apps/studio/generation/adapters/groq.test.ts +80 -0
- package/apps/studio/generation/adapters/groq.ts +247 -0
- package/apps/studio/generation/audio-library.test.ts +95 -0
- package/apps/studio/generation/audio-library.ts +156 -0
- package/apps/studio/generation/captions.test.ts +78 -0
- package/apps/studio/generation/captions.ts +132 -0
- package/apps/studio/generation/download.ts +76 -0
- package/apps/studio/generation/elevenlabs.test.ts +223 -0
- package/apps/studio/generation/gemini.test.ts +350 -0
- package/apps/studio/generation/jobs.test.ts +128 -0
- package/apps/studio/generation/jobs.ts +243 -0
- package/apps/studio/generation/keys.test.ts +75 -0
- package/apps/studio/generation/keys.ts +162 -0
- package/apps/studio/generation/prefs.test.ts +95 -0
- package/apps/studio/generation/prefs.ts +82 -0
- package/apps/studio/generation/registry.ts +88 -0
- package/apps/studio/generation/types.test.ts +123 -0
- package/apps/studio/generation/types.ts +266 -0
- package/apps/studio/generation/whisper-models.test.ts +152 -0
- package/apps/studio/generation/whisper-models.ts +257 -0
- package/apps/studio/generation/whisper-spike-results.md +61 -0
- package/apps/studio/git/endpoints.ts +68 -7
- package/apps/studio/git/service.ts +199 -21
- package/apps/studio/github/service.ts +67 -0
- package/apps/studio/handoff.ts +3 -2
- package/apps/studio/http.ts +1039 -22
- package/apps/studio/input-router.tsx +10 -0
- package/apps/studio/inspect.ts +53 -1
- package/apps/studio/media/intro.mp4 +0 -0
- package/apps/studio/media-commit-chain.ts +119 -0
- package/apps/studio/paths.ts +20 -0
- package/apps/studio/photo/filters.ts +285 -0
- package/apps/studio/photo/pipeline.ts +607 -0
- package/apps/studio/photo/schema.ts +367 -0
- package/apps/studio/photo-store.ts +154 -0
- package/apps/studio/readiness.ts +108 -20
- package/apps/studio/runtime-bundle.ts +29 -6
- package/apps/studio/scaffold-design.ts +1145 -0
- package/apps/studio/server.ts +18 -2
- package/apps/studio/stickers/figjam-doodle/manifest.json +104 -0
- package/apps/studio/stickers/figjam-doodle/slice1.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice10.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice11.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice12.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice13.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice14.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice15.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice16.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice17.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice18.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice19.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice2.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice20.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice21.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice22.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice23.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice24.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice3.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice4.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice5.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice6.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice7.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice8.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice9.png +0 -0
- package/apps/studio/stickers/life-style/best.png +0 -0
- package/apps/studio/stickers/life-style/come-on.png +0 -0
- package/apps/studio/stickers/life-style/cut.png +0 -0
- package/apps/studio/stickers/life-style/detox.png +0 -0
- package/apps/studio/stickers/life-style/just.png +0 -0
- package/apps/studio/stickers/life-style/manifest.json +68 -0
- package/apps/studio/stickers/life-style/mirror.png +0 -0
- package/apps/studio/stickers/life-style/nice.png +0 -0
- package/apps/studio/stickers/life-style/objects.png +0 -0
- package/apps/studio/stickers/life-style/ok.png +0 -0
- package/apps/studio/stickers/life-style/queen.png +0 -0
- package/apps/studio/stickers/life-style/star.png +0 -0
- package/apps/studio/stickers/life-style/sun.png +0 -0
- package/apps/studio/stickers/life-style/water.png +0 -0
- package/apps/studio/stickers/life-style/yeah.png +0 -0
- package/apps/studio/stickers/life-style/you-can.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/check-the-deets.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/cut-it.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/dope.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/fresh.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/hot.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/idea.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/keep-exploring.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/killed-it.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/love-it.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/manifest.json +88 -0
- package/apps/studio/stickers/opposing-thoughts/not-sure.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/ok.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/pure-gold.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/save-for-later.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/steal-this.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/take-a-peek.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/this-or-that.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/thoughts.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/vibes.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/winner.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/wip.png +0 -0
- package/apps/studio/stickers/project-status/group-100.png +0 -0
- package/apps/studio/stickers/project-status/group-101.png +0 -0
- package/apps/studio/stickers/project-status/group-102.png +0 -0
- package/apps/studio/stickers/project-status/group-103.png +0 -0
- package/apps/studio/stickers/project-status/group-104.png +0 -0
- package/apps/studio/stickers/project-status/group-105.png +0 -0
- package/apps/studio/stickers/project-status/group-106.png +0 -0
- package/apps/studio/stickers/project-status/group-107.png +0 -0
- package/apps/studio/stickers/project-status/group-108.png +0 -0
- package/apps/studio/stickers/project-status/group-109.png +0 -0
- package/apps/studio/stickers/project-status/group-110.png +0 -0
- package/apps/studio/stickers/project-status/group-111.png +0 -0
- package/apps/studio/stickers/project-status/group-112.png +0 -0
- package/apps/studio/stickers/project-status/group-113.png +0 -0
- package/apps/studio/stickers/project-status/group-114.png +0 -0
- package/apps/studio/stickers/project-status/group-115.png +0 -0
- package/apps/studio/stickers/project-status/group-117.png +0 -0
- package/apps/studio/stickers/project-status/group-118.png +0 -0
- package/apps/studio/stickers/project-status/group-119.png +0 -0
- package/apps/studio/stickers/project-status/group-120.png +0 -0
- package/apps/studio/stickers/project-status/group-121.png +0 -0
- package/apps/studio/stickers/project-status/group-122.png +0 -0
- package/apps/studio/stickers/project-status/group-41.png +0 -0
- package/apps/studio/stickers/project-status/group-42.png +0 -0
- package/apps/studio/stickers/project-status/group-43.png +0 -0
- package/apps/studio/stickers/project-status/group-44.png +0 -0
- package/apps/studio/stickers/project-status/group-45.png +0 -0
- package/apps/studio/stickers/project-status/group-46.png +0 -0
- package/apps/studio/stickers/project-status/group-47.png +0 -0
- package/apps/studio/stickers/project-status/group-48.png +0 -0
- package/apps/studio/stickers/project-status/group-49.png +0 -0
- package/apps/studio/stickers/project-status/group-50.png +0 -0
- package/apps/studio/stickers/project-status/group-51.png +0 -0
- package/apps/studio/stickers/project-status/group-52.png +0 -0
- package/apps/studio/stickers/project-status/group-53.png +0 -0
- package/apps/studio/stickers/project-status/group-54.png +0 -0
- package/apps/studio/stickers/project-status/group-55.png +0 -0
- package/apps/studio/stickers/project-status/group-56.png +0 -0
- package/apps/studio/stickers/project-status/group-57.png +0 -0
- package/apps/studio/stickers/project-status/group-58.png +0 -0
- package/apps/studio/stickers/project-status/group-59.png +0 -0
- package/apps/studio/stickers/project-status/group-60.png +0 -0
- package/apps/studio/stickers/project-status/group-61.png +0 -0
- package/apps/studio/stickers/project-status/group-62.png +0 -0
- package/apps/studio/stickers/project-status/group-63.png +0 -0
- package/apps/studio/stickers/project-status/group-64.png +0 -0
- package/apps/studio/stickers/project-status/group-65.png +0 -0
- package/apps/studio/stickers/project-status/group-66.png +0 -0
- package/apps/studio/stickers/project-status/group-67.png +0 -0
- package/apps/studio/stickers/project-status/group-68.png +0 -0
- package/apps/studio/stickers/project-status/group-69.png +0 -0
- package/apps/studio/stickers/project-status/group-70.png +0 -0
- package/apps/studio/stickers/project-status/group-71.png +0 -0
- package/apps/studio/stickers/project-status/group-72.png +0 -0
- package/apps/studio/stickers/project-status/group-73.png +0 -0
- package/apps/studio/stickers/project-status/group-74.png +0 -0
- package/apps/studio/stickers/project-status/group-75.png +0 -0
- package/apps/studio/stickers/project-status/group-76.png +0 -0
- package/apps/studio/stickers/project-status/group-77.png +0 -0
- package/apps/studio/stickers/project-status/group-78.png +0 -0
- package/apps/studio/stickers/project-status/group-79.png +0 -0
- package/apps/studio/stickers/project-status/group-80.png +0 -0
- package/apps/studio/stickers/project-status/group-81.png +0 -0
- package/apps/studio/stickers/project-status/group-82.png +0 -0
- package/apps/studio/stickers/project-status/group-83.png +0 -0
- package/apps/studio/stickers/project-status/group-84.png +0 -0
- package/apps/studio/stickers/project-status/group-85.png +0 -0
- package/apps/studio/stickers/project-status/group-86.png +0 -0
- package/apps/studio/stickers/project-status/group-87.png +0 -0
- package/apps/studio/stickers/project-status/group-88.png +0 -0
- package/apps/studio/stickers/project-status/group-89.png +0 -0
- package/apps/studio/stickers/project-status/group-90.png +0 -0
- package/apps/studio/stickers/project-status/group-91.png +0 -0
- package/apps/studio/stickers/project-status/group-92.png +0 -0
- package/apps/studio/stickers/project-status/group-93.png +0 -0
- package/apps/studio/stickers/project-status/group-94.png +0 -0
- package/apps/studio/stickers/project-status/group-96.png +0 -0
- package/apps/studio/stickers/project-status/group-97.png +0 -0
- package/apps/studio/stickers/project-status/group-98.png +0 -0
- package/apps/studio/stickers/project-status/group-99.png +0 -0
- package/apps/studio/stickers/project-status/manifest.json +328 -0
- package/apps/studio/test/_helpers.ts +15 -2
- package/apps/studio/test/acp-bootstrap-brief.test.ts +11 -0
- package/apps/studio/test/acp-bridge.test.ts +34 -1
- package/apps/studio/test/acp-commands.test.ts +2 -1
- package/apps/studio/test/acp-env.test.ts +30 -0
- package/apps/studio/test/acp-plugin-bootstrap.test.ts +23 -57
- package/apps/studio/test/acp-session-plugins.test.ts +72 -1
- package/apps/studio/test/annotation-strokes-command.test.ts +17 -0
- package/apps/studio/test/annotations-layer.test.ts +174 -0
- package/apps/studio/test/asset-api.test.ts +3 -3
- package/apps/studio/test/canvas-edit.test.ts +17 -6
- package/apps/studio/test/canvas-origin-gate.test.ts +50 -0
- package/apps/studio/test/csp-canvas-shell.test.ts +11 -0
- package/apps/studio/test/csrf-write-guard.test.ts +23 -1
- package/apps/studio/test/design-setup-readiness.test.ts +155 -0
- package/apps/studio/test/dynamic-text-edit.test.ts +162 -0
- package/apps/studio/test/edit-source-command.test.ts +23 -0
- package/apps/studio/test/element-structural-edit.test.ts +154 -0
- package/apps/studio/test/fixtures/fake-claude-auth.mjs +13 -0
- package/apps/studio/test/footage-store.test.ts +100 -0
- package/apps/studio/test/generate-route.test.ts +106 -0
- package/apps/studio/test/git-branches.test.ts +97 -0
- package/apps/studio/test/github-api.test.ts +56 -1
- package/apps/studio/test/import-asset-browser.test.ts +64 -0
- package/apps/studio/test/import-asset-route.test.ts +71 -0
- package/apps/studio/test/import-asset.test.ts +399 -0
- package/apps/studio/test/import-brand-browser.test.ts +88 -0
- package/apps/studio/test/import-brand-route.test.ts +120 -0
- package/apps/studio/test/import-brand.test.ts +206 -0
- package/apps/studio/test/import-tokens.test.ts +722 -0
- package/apps/studio/test/input-router.test.ts +33 -0
- package/apps/studio/test/inspect-script-syntax.test.ts +53 -0
- package/apps/studio/test/media-commit-chain.test.ts +210 -0
- package/apps/studio/test/photo-bg-remove-validation.test.ts +71 -0
- package/apps/studio/test/photo-canvas-bundle.test.ts +61 -0
- package/apps/studio/test/photo-edit-api.test.ts +201 -0
- package/apps/studio/test/photo-filters.test.ts +149 -0
- package/apps/studio/test/photo-pipeline.test.ts +106 -0
- package/apps/studio/test/photo-taxonomy.test.ts +96 -0
- package/apps/studio/test/read-annotations.test.ts +164 -0
- package/apps/studio/test/readiness.test.ts +13 -11
- package/apps/studio/test/scaffold-design.test.ts +122 -0
- package/apps/studio/test/shell-importmap.test.ts +49 -0
- package/apps/studio/test/text-editability-stamp.test.ts +131 -0
- package/apps/studio/test/timeline-parse.test.ts +57 -0
- package/apps/studio/test/tool-palette-insert-anchor.test.ts +5 -3
- package/apps/studio/test/tour-overlay.test.tsx +16 -0
- package/apps/studio/test/undo-stack.test.ts +33 -0
- package/apps/studio/test/video-asset.test.ts +5 -5
- package/apps/studio/test/video-render-bridge.test.ts +23 -1
- package/apps/studio/text-caret.ts +239 -0
- package/apps/studio/tool-palette.tsx +49 -21
- package/apps/studio/ui-prefs.ts +130 -0
- package/apps/studio/undo-stack.ts +94 -2
- package/apps/studio/use-annotation-resize.tsx +4 -4
- package/apps/studio/use-canvas-media-drop.tsx +40 -1
- package/apps/studio/use-chrome-visibility.tsx +8 -2
- package/apps/studio/use-selection-set.tsx +21 -0
- package/apps/studio/video-comp.tsx +48 -7
- package/apps/studio/whats-new.json +149 -0
- package/apps/studio/ws.ts +5 -0
- package/cli/bin/maude.mjs +6 -6
- package/cli/commands/design.mjs +67 -3
- package/cli/lib/gitignore-block.mjs +2 -0
- package/cli/lib/pkg-root.mjs +107 -0
- package/cli/lib/pkg-root.test.mjs +79 -0
- package/cli/lib/reconstruct-toolset.test.mjs +194 -0
- package/cli/lib/update-check.mjs +8 -0
- package/package.json +13 -11
- package/plugins/design/dependencies.json +18 -0
- package/plugins/design/templates/_shell.html +1 -0
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
// not-connected explainer (where a user actually hits the wall). Both also use it
|
|
8
8
|
// as the persistent re-check surface — `refresh()` re-probes without a reinstall.
|
|
9
9
|
|
|
10
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
10
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
11
|
+
import { getClaudeAutoSetup, isNativeApp, setClaudeAutoSetup } from '../github.js';
|
|
11
12
|
|
|
12
13
|
/** Fetch + cache the readiness report. `refresh()` re-probes (the re-check button). */
|
|
13
14
|
export function useReadiness(enabled = true) {
|
|
@@ -82,7 +83,165 @@ function Inline({ text }) {
|
|
|
82
83
|
return <>{parts}</>;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
// DDR-166 T0d — a bounded, cancelable poll after "Sign in" is clicked. Capped
|
|
87
|
+
// duration (not indefinite), single-flight (the button disables while
|
|
88
|
+
// polling), and its copy is static text — no animation, so it costs nothing
|
|
89
|
+
// under prefers-reduced-motion.
|
|
90
|
+
const SIGNIN_POLL_MS = 2000;
|
|
91
|
+
const SIGNIN_POLL_MAX_MS = 120000;
|
|
92
|
+
// The installer itself is fire-and-forget server-side (avoids Bun's default
|
|
93
|
+
// 10s idle timeout on a slow network) — poll for its result the same way.
|
|
94
|
+
const INSTALL_POLL_MS = 1500;
|
|
95
|
+
const INSTALL_POLL_MAX_MS = 90000;
|
|
96
|
+
|
|
97
|
+
// DDR-166 T0c/T0d — one component drives both the "install then sign in"
|
|
98
|
+
// chain (mode='install') and the "sign in only" case (mode='signin'), since
|
|
99
|
+
// the poll-after-signin logic is identical either way. The install step
|
|
100
|
+
// itself is a single distinct network call, not a loop — only the sign-in
|
|
101
|
+
// half needs polling (the browser-OAuth completion signal).
|
|
102
|
+
function SetupAction({ mode, refresh }) {
|
|
103
|
+
const [phase, setPhase] = useState('idle'); // idle | installing | waiting | error
|
|
104
|
+
const [error, setError] = useState(null);
|
|
105
|
+
const timerRef = useRef({ interval: null, deadline: 0 });
|
|
106
|
+
|
|
107
|
+
const stopPoll = () => {
|
|
108
|
+
if (timerRef.current.interval) clearInterval(timerRef.current.interval);
|
|
109
|
+
timerRef.current.interval = null;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const pollForSignin = () => {
|
|
113
|
+
setPhase('waiting');
|
|
114
|
+
timerRef.current.deadline = Date.now() + SIGNIN_POLL_MAX_MS;
|
|
115
|
+
timerRef.current.interval = setInterval(async () => {
|
|
116
|
+
if (Date.now() > timerRef.current.deadline) {
|
|
117
|
+
stopPoll();
|
|
118
|
+
setPhase('error');
|
|
119
|
+
setError('Sign-in timed out — try again.');
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const report = await refresh();
|
|
123
|
+
const claudeItem = report?.items?.find((i) => i.id === 'claude');
|
|
124
|
+
if (claudeItem?.status === 'present') stopPoll();
|
|
125
|
+
}, SIGNIN_POLL_MS);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const runSignin = async () => {
|
|
129
|
+
const res = await fetch('/_api/claude/signin', { method: 'POST' })
|
|
130
|
+
.then((r) => r.json())
|
|
131
|
+
.catch(() => ({ ok: false, reason: 'Could not reach Maude.' }));
|
|
132
|
+
if (!res.ok) {
|
|
133
|
+
setPhase('error');
|
|
134
|
+
setError(res.reason || 'Could not start sign-in.');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
pollForSignin();
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const pollForInstall = () => {
|
|
141
|
+
setPhase('installing');
|
|
142
|
+
timerRef.current.deadline = Date.now() + INSTALL_POLL_MAX_MS;
|
|
143
|
+
timerRef.current.interval = setInterval(async () => {
|
|
144
|
+
if (Date.now() > timerRef.current.deadline) {
|
|
145
|
+
stopPoll();
|
|
146
|
+
setPhase('error');
|
|
147
|
+
setError('Install timed out — you can also run the command below yourself.');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const state = await fetch('/_api/claude/install-status')
|
|
151
|
+
.then((r) => r.json())
|
|
152
|
+
.catch(() => null);
|
|
153
|
+
if (!state || state.phase !== 'done') return; // still running
|
|
154
|
+
stopPoll();
|
|
155
|
+
if (!state.ok) {
|
|
156
|
+
setPhase('error');
|
|
157
|
+
setError(state.reason || 'Install failed — you can also run the command below yourself.');
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// One click covers both steps: only on verified-fresh install success
|
|
161
|
+
// does this move straight into sign-in with no second click needed.
|
|
162
|
+
await runSignin();
|
|
163
|
+
}, INSTALL_POLL_MS);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const start = async () => {
|
|
167
|
+
setError(null);
|
|
168
|
+
if (mode === 'install') {
|
|
169
|
+
const res = await fetch('/_api/claude/install', { method: 'POST' })
|
|
170
|
+
.then((r) => r.json())
|
|
171
|
+
.catch(() => ({ ok: false, reason: 'Could not reach Maude.' }));
|
|
172
|
+
if (!res.ok) {
|
|
173
|
+
setPhase('error');
|
|
174
|
+
setError(res.reason || 'Could not start the installer.');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
pollForInstall();
|
|
178
|
+
} else {
|
|
179
|
+
await runSignin();
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const cancel = async () => {
|
|
184
|
+
stopPoll();
|
|
185
|
+
setPhase('idle');
|
|
186
|
+
await fetch('/_api/claude/signin-cancel', { method: 'POST' }).catch(() => {});
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
useEffect(() => () => stopPoll(), []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
190
|
+
|
|
191
|
+
if (phase === 'installing') {
|
|
192
|
+
return (
|
|
193
|
+
<span className="rdy-fix">
|
|
194
|
+
<span className="rdy-fix-tx">Installing Claude Code…</span>
|
|
195
|
+
</span>
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
if (phase === 'waiting') {
|
|
199
|
+
return (
|
|
200
|
+
<span className="rdy-fix">
|
|
201
|
+
<span className="rdy-fix-tx">Waiting for you to finish signing in in your browser…</span>
|
|
202
|
+
<button type="button" className="rdy-copy" onClick={cancel}>
|
|
203
|
+
Cancel
|
|
204
|
+
</button>
|
|
205
|
+
</span>
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
return (
|
|
209
|
+
<span className="rdy-fix">
|
|
210
|
+
{error ? <span className="rdy-fix-tx rdy-fix-tx--err">{error}</span> : null}
|
|
211
|
+
<button
|
|
212
|
+
type="button"
|
|
213
|
+
className="rdy-signin"
|
|
214
|
+
data-testid={mode === 'install' ? 'acp-setup-install' : 'acp-setup-signin'}
|
|
215
|
+
onClick={start}
|
|
216
|
+
>
|
|
217
|
+
{mode === 'install' ? 'Set up AI editing' : 'Sign in to Claude'}
|
|
218
|
+
</button>
|
|
219
|
+
</span>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function InstallCommand({ command }) {
|
|
224
|
+
const [copied, setCopied] = useState(false);
|
|
225
|
+
const copy = () => {
|
|
226
|
+
navigator.clipboard?.writeText(command).then(
|
|
227
|
+
() => {
|
|
228
|
+
setCopied(true);
|
|
229
|
+
setTimeout(() => setCopied(false), 1500);
|
|
230
|
+
},
|
|
231
|
+
() => {}
|
|
232
|
+
);
|
|
233
|
+
};
|
|
234
|
+
return (
|
|
235
|
+
<span className="rdy-cmd">
|
|
236
|
+
<code className="rdy-cmd-tx">{command}</code>
|
|
237
|
+
<button type="button" className="rdy-copy" onClick={copy} aria-label="Copy install command">
|
|
238
|
+
{copied ? 'Copied' : 'Copy'}
|
|
239
|
+
</button>
|
|
240
|
+
</span>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function Row({ item, refresh }) {
|
|
86
245
|
const [copied, setCopied] = useState(false);
|
|
87
246
|
const copyFix = () => {
|
|
88
247
|
const cmds = item.remediation?.replace(/`/g, '') ?? '';
|
|
@@ -95,7 +254,10 @@ function Row({ item }) {
|
|
|
95
254
|
);
|
|
96
255
|
};
|
|
97
256
|
return (
|
|
98
|
-
<li
|
|
257
|
+
<li
|
|
258
|
+
className={`rdy-row rdy-row--${item.status}${item.required ? '' : ' rdy-row--opt'}`}
|
|
259
|
+
data-testid={`rdy-row-${item.id}`}
|
|
260
|
+
>
|
|
99
261
|
<span className="rdy-ic" aria-hidden="true">
|
|
100
262
|
<StatusIcon status={item.status} />
|
|
101
263
|
</span>
|
|
@@ -109,11 +271,33 @@ function Row({ item }) {
|
|
|
109
271
|
<span className="rdy-fix-tx">
|
|
110
272
|
<Inline text={item.remediation} />
|
|
111
273
|
</span>
|
|
112
|
-
|
|
113
|
-
{
|
|
114
|
-
|
|
274
|
+
{!item.installCommand && !item.action ? (
|
|
275
|
+
<button type="button" className="rdy-copy" onClick={copyFix} aria-label={`Copy the fix for ${item.label}`}>
|
|
276
|
+
{copied ? 'Copied' : 'Copy'}
|
|
277
|
+
</button>
|
|
278
|
+
) : null}
|
|
279
|
+
</span>
|
|
280
|
+
) : null}
|
|
281
|
+
{item.action === 'signin' && item.resolvedPath ? (
|
|
282
|
+
<span className="rdy-fix-tx rdy-resolved-path">
|
|
283
|
+
{item.resolvedViaMaude ? 'Installed by Maude: ' : 'Found on your PATH: '}
|
|
284
|
+
<code>{item.resolvedPath}</code>
|
|
115
285
|
</span>
|
|
116
286
|
) : null}
|
|
287
|
+
{(item.action === 'install' || item.action === 'signin') && refresh ? (
|
|
288
|
+
<SetupAction mode={item.action} refresh={refresh} />
|
|
289
|
+
) : null}
|
|
290
|
+
{item.installCommand ? (
|
|
291
|
+
<>
|
|
292
|
+
{item.action === 'install' ? (
|
|
293
|
+
<span className="rdy-fix-tx rdy-fallback-label">
|
|
294
|
+
Clicking above runs this command, then opens your browser to sign in. Prefer to do it
|
|
295
|
+
yourself?
|
|
296
|
+
</span>
|
|
297
|
+
) : null}
|
|
298
|
+
<InstallCommand command={item.installCommand} />
|
|
299
|
+
</>
|
|
300
|
+
) : null}
|
|
117
301
|
</span>
|
|
118
302
|
</li>
|
|
119
303
|
);
|
|
@@ -124,7 +308,7 @@ export default function ReadinessList({ report, loading, refresh }) {
|
|
|
124
308
|
<div className="rdy">
|
|
125
309
|
<ul className="rdy-list">
|
|
126
310
|
{report?.items?.map((it) => (
|
|
127
|
-
<Row key={it.id} item={it} />
|
|
311
|
+
<Row key={it.id} item={it} refresh={refresh} />
|
|
128
312
|
))}
|
|
129
313
|
</ul>
|
|
130
314
|
{refresh ? (
|
|
@@ -138,6 +322,41 @@ export default function ReadinessList({ report, loading, refresh }) {
|
|
|
138
322
|
);
|
|
139
323
|
}
|
|
140
324
|
|
|
325
|
+
// DDR-166 Decision 5 — the settings-UI opt-out for the auto-install/auto-
|
|
326
|
+
// sign-in buttons above. DEFAULT ON. Native-only (the toggle is backed by a
|
|
327
|
+
// Tauri command); a terminal-launched `maude design serve` web session has
|
|
328
|
+
// no automated action to opt out of in the first place.
|
|
329
|
+
function AutoSetupToggle() {
|
|
330
|
+
const [on, setOn] = useState(true);
|
|
331
|
+
useEffect(() => {
|
|
332
|
+
let alive = true;
|
|
333
|
+
getClaudeAutoSetup()
|
|
334
|
+
.then((v) => alive && setOn(v !== false))
|
|
335
|
+
.catch(() => {});
|
|
336
|
+
return () => {
|
|
337
|
+
alive = false;
|
|
338
|
+
};
|
|
339
|
+
}, []);
|
|
340
|
+
if (!isNativeApp()) return null;
|
|
341
|
+
return (
|
|
342
|
+
<label className="rdy-autosetup-toggle">
|
|
343
|
+
<input
|
|
344
|
+
type="checkbox"
|
|
345
|
+
checked={on}
|
|
346
|
+
onChange={(e) => {
|
|
347
|
+
const next = e.target.checked;
|
|
348
|
+
setOn(next);
|
|
349
|
+
setClaudeAutoSetup(next).catch(() => setOn(!next));
|
|
350
|
+
}}
|
|
351
|
+
/>
|
|
352
|
+
<span>
|
|
353
|
+
Offer to install Claude Code and sign in automatically. Turn off to see only the copy-paste
|
|
354
|
+
command — takes effect next launch or project switch.
|
|
355
|
+
</span>
|
|
356
|
+
</label>
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
141
360
|
// Standalone readiness modal reachable any time from Help ▸ Check AI editing
|
|
142
361
|
// readiness… (DDR-128, T6 — the persistent re-check surface, not gated on
|
|
143
362
|
// first-run or a disconnected chat). Reuses the shared help-modal chrome (backdrop
|
|
@@ -182,6 +401,7 @@ export function ReadinessDialog({ open, onClose }) {
|
|
|
182
401
|
{loading ? 'Checking…' : "Couldn't reach the readiness probe."}
|
|
183
402
|
</p>
|
|
184
403
|
)}
|
|
404
|
+
<AutoSetupToggle />
|
|
185
405
|
</div>
|
|
186
406
|
</div>
|
|
187
407
|
</div>
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
import { useEffect, useRef, useState } from 'react';
|
|
21
21
|
|
|
22
|
-
import { appRecentProjects, isNativeApp, openLocalProject, pickDirectory } from '../github.js';
|
|
22
|
+
import { appRecentProjects, isNativeApp, openGitHubUrl, openLocalProject, pickDirectory } from '../github.js';
|
|
23
23
|
|
|
24
24
|
const SHARED = new Set(['main', 'master']);
|
|
25
25
|
|
|
@@ -43,6 +43,10 @@ function Icon({ name, size = 16, className }) {
|
|
|
43
43
|
// refresh drafts — a circular arrow.
|
|
44
44
|
refresh: (<><path d="M12.5 8a4.5 4.5 0 1 1-1.3-3.2" /><polyline points="12.8 2.5 12.8 5 10.3 5" /></>),
|
|
45
45
|
spinner: <path d="M8 2.2a5.8 5.8 0 1 0 5.8 5.8" />,
|
|
46
|
+
// "get latest" — pull the shared version's new commits down.
|
|
47
|
+
download: (<><line x1="8" y1="2.5" x2="8" y2="10.5" /><polyline points="5 7.5 8 10.5 11 7.5" /><line x1="3.5" y1="13.2" x2="12.5" y2="13.2" /></>),
|
|
48
|
+
// dismiss (×) — used by the "continue on <draft>" resume nudge.
|
|
49
|
+
close: (<><line x1="4" y1="4" x2="12" y2="12" /><line x1="12" y1="4" x2="4" y2="12" /></>),
|
|
46
50
|
}[name];
|
|
47
51
|
return (
|
|
48
52
|
<svg className={className} width={size} height={size} viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
@@ -93,7 +97,7 @@ async function postJson(url, body, opts = {}) {
|
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
99
|
|
|
96
|
-
export default function RepoBranchSwitcher({ project, liveBranch }) {
|
|
100
|
+
export default function RepoBranchSwitcher({ project, liveBranch, remoteSync, onGetLatest }) {
|
|
97
101
|
const native = isNativeApp();
|
|
98
102
|
const [status, setStatus] = useState(null); // { repo, branch }
|
|
99
103
|
const [branches, setBranches] = useState([]);
|
|
@@ -103,6 +107,34 @@ export default function RepoBranchSwitcher({ project, liveBranch }) {
|
|
|
103
107
|
const [draftName, setDraftName] = useState('');
|
|
104
108
|
const [foldConfirm, setFoldConfirm] = useState(false);
|
|
105
109
|
const [folding, setFolding] = useState('');
|
|
110
|
+
// After a GitHub-remote fold: { url, number } (PR opened) or { message } (draft
|
|
111
|
+
// pushed but no PR). Keeps the confirm sheet open to show the result (DDR-162).
|
|
112
|
+
const [prResult, setPrResult] = useState(null);
|
|
113
|
+
const [prCopied, setPrCopied] = useState(false);
|
|
114
|
+
// Get-latest (pull) busy state for the dock nudge.
|
|
115
|
+
const [pulling, setPulling] = useState(false);
|
|
116
|
+
// "Continue on <draft>?" nudge — dismissed for this session once the user opts out.
|
|
117
|
+
const [resumeDismissed, setResumeDismissed] = useState(false);
|
|
118
|
+
|
|
119
|
+
// Open the PR in the OS browser. A WKWebView anchor can't reach the default browser,
|
|
120
|
+
// so native goes through the Tauri opener (github.com host-locked in Rust); an older
|
|
121
|
+
// desktop build without that command falls back to copy-to-clipboard. Web just opens.
|
|
122
|
+
async function reviewPr(url) {
|
|
123
|
+
if (!isNativeApp()) {
|
|
124
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
await openGitHubUrl(url);
|
|
129
|
+
} catch {
|
|
130
|
+
try {
|
|
131
|
+
await navigator.clipboard.writeText(url);
|
|
132
|
+
setPrCopied(true);
|
|
133
|
+
} catch {
|
|
134
|
+
/* clipboard blocked — the URL is shown selectable in the sheet */
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
106
138
|
const [busy, setBusy] = useState(false);
|
|
107
139
|
const [switching, setSwitching] = useState('');
|
|
108
140
|
const [err, setErr] = useState('');
|
|
@@ -248,17 +280,43 @@ export default function RepoBranchSwitcher({ project, liveBranch }) {
|
|
|
248
280
|
else { setErr(r.json?.error || 'Could not create the draft.'); setBusy(false); }
|
|
249
281
|
}
|
|
250
282
|
|
|
251
|
-
// "
|
|
283
|
+
// "Get latest" from the dock nudge — pull the shared version's new commits. Reuses
|
|
284
|
+
// the app's pull handler (onGetLatest = gitGetLatest): on success it re-probes so the
|
|
285
|
+
// nudge clears; a content conflict opens the visual resolver (handled in app.jsx).
|
|
286
|
+
async function getLatest() {
|
|
287
|
+
if (pulling || !onGetLatest) return;
|
|
288
|
+
setPulling(true);
|
|
289
|
+
setErr('');
|
|
290
|
+
const r = await onGetLatest();
|
|
291
|
+
setPulling(false);
|
|
292
|
+
if (r && !r.ok && !r.conflict)
|
|
293
|
+
setErr(r.status === 401 || r.authRequired ? 'Sign in with GitHub to get the latest.' : r.error || 'Could not get the latest.');
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// "Add this draft to the Shared version" (Task 7 / DDR-162). On a GitHub remote this
|
|
297
|
+
// opens a pull request (the merge happens on GitHub, post-review) — surface the PR
|
|
298
|
+
// link and keep the sheet open. A local project merges directly (reload). A draft that
|
|
299
|
+
// pushed but couldn't open a PR (no sign-in / non-github) shows a heads-up.
|
|
252
300
|
async function foldDraft() {
|
|
253
|
-
setFoldConfirm(false);
|
|
254
301
|
setFolding(branch);
|
|
255
302
|
setErr('');
|
|
256
|
-
const r = await postJson('/_api/git/fold', { name: branch });
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
303
|
+
const r = await postJson('/_api/git/fold', { name: branch }, { timeoutMs: 45000 });
|
|
304
|
+
const j = r.json;
|
|
305
|
+
if (r.ok && j?.ok && j.prUrl) {
|
|
306
|
+
setPrResult({ url: j.prUrl, number: j.prNumber, repo: j.repo });
|
|
307
|
+
setFolding('');
|
|
308
|
+
reloadBranches(); // the draft still exists (the PR references it) — keep the list
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (r.ok && j?.ok && j.prUnavailable) {
|
|
312
|
+
setPrResult({ message: j.error || 'Draft published, but the pull request could not be opened.' });
|
|
260
313
|
setFolding('');
|
|
314
|
+
reloadBranches();
|
|
315
|
+
return;
|
|
261
316
|
}
|
|
317
|
+
if (r.ok && j?.ok) { window.location.reload(); return; } // local merge (no remote)
|
|
318
|
+
setErr(r.status === 401 ? `Sign in with GitHub to add “${branch}” to ${sharedName}.` : j?.error || 'Could not add the branch.');
|
|
319
|
+
setFolding('');
|
|
262
320
|
}
|
|
263
321
|
|
|
264
322
|
async function switchRepo(path) {
|
|
@@ -282,6 +340,16 @@ export default function RepoBranchSwitcher({ project, liveBranch }) {
|
|
|
282
340
|
|
|
283
341
|
const slug = slugify(draftName);
|
|
284
342
|
const currentDraft = onShared ? null : branches.find((b) => b.current);
|
|
343
|
+
// On the Shared version with a draft around? Offer to jump back to the most
|
|
344
|
+
// recently-worked local draft. Maude shows whatever branch HEAD is, so after a
|
|
345
|
+
// merge / Get-latest you land on the Shared version — this saves the manual switch
|
|
346
|
+
// back to the draft you were iterating on. Dismissible for the session.
|
|
347
|
+
const resumeDraft =
|
|
348
|
+
onShared && !resumeDismissed && !switching && !folding
|
|
349
|
+
? [...branches]
|
|
350
|
+
.filter((b) => !SHARED.has(b.name) && b.where !== 'remote')
|
|
351
|
+
.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0))[0]
|
|
352
|
+
: null;
|
|
285
353
|
|
|
286
354
|
// Search-miss (DDR-133, Task 4): a typed name that matches no LOCAL or already-
|
|
287
355
|
// fetched remote branch offers an explicit remote search (the bounded fetch),
|
|
@@ -316,6 +384,23 @@ export default function RepoBranchSwitcher({ project, liveBranch }) {
|
|
|
316
384
|
|
|
317
385
|
return (
|
|
318
386
|
<div className="rb-dock-wrap">
|
|
387
|
+
{remoteSync?.remoteAhead && !switching && !folding && (
|
|
388
|
+
<button type="button" data-testid="switcher-get-latest" className="btn btn--primary rb-getlatest" onClick={getLatest} disabled={pulling} title={`Get the latest ${sharedName}`}>
|
|
389
|
+
<Icon name={pulling ? 'spinner' : 'download'} size={14} className={pulling ? 'rb-spin' : ''} />
|
|
390
|
+
<span className="rb-getlatest-tx">{pulling ? 'Getting the latest…' : 'Get latest'}</span>
|
|
391
|
+
{!pulling && remoteSync.behind > 0 && <span className="rb-getlatest-sub">{remoteSync.behind} new on {sharedName}</span>}
|
|
392
|
+
</button>
|
|
393
|
+
)}
|
|
394
|
+
{resumeDraft && (
|
|
395
|
+
<div className="rb-resume" data-testid="switcher-resume">
|
|
396
|
+
<button type="button" className="rb-resume-go" onClick={() => switchDraft(resumeDraft.name)} title={`Switch to ${resumeDraft.name}`}>
|
|
397
|
+
<span className="rb-resume-icon"><Icon name="draft" size={13} /></span>
|
|
398
|
+
<span className="rb-resume-tx">Continue on <b>{resumeDraft.name}</b></span>
|
|
399
|
+
<Icon name="chevron-right" size={12} className="rb-resume-arrow" />
|
|
400
|
+
</button>
|
|
401
|
+
<button type="button" className="rb-resume-x" data-testid="switcher-resume-dismiss" aria-label="Dismiss" onClick={() => setResumeDismissed(true)}><Icon name="close" size={12} /></button>
|
|
402
|
+
</div>
|
|
403
|
+
)}
|
|
319
404
|
<div className="rb-dock" ref={rootRef}>
|
|
320
405
|
{open && (
|
|
321
406
|
<div className="rb-pop rb-pop--up" id="rb-switch-pop" role="menu" aria-label="Switch project or version" data-testid="repo-switcher-popup">
|
|
@@ -376,7 +461,7 @@ export default function RepoBranchSwitcher({ project, liveBranch }) {
|
|
|
376
461
|
</span>
|
|
377
462
|
<Icon name="check" size={14} className="rb-pop-check" />
|
|
378
463
|
</button>
|
|
379
|
-
<button type="button" data-testid="switcher-merge" className="rb-fold" role="menuitem" onClick={() => { setOpen(false); setFoldConfirm(true); }}>
|
|
464
|
+
<button type="button" data-testid="switcher-merge" className="rb-fold" role="menuitem" onClick={() => { setOpen(false); setErr(''); setPrResult(null); setPrCopied(false); setFoldConfirm(true); }}>
|
|
380
465
|
<span className="rb-fold-icon"><Icon name="arrow-up-to-line" size={15} /></span>
|
|
381
466
|
<span className="rb-fold-tx">
|
|
382
467
|
<span className="rb-fold-title">Merge this branch → {sharedName}</span>
|
|
@@ -459,19 +544,46 @@ export default function RepoBranchSwitcher({ project, liveBranch }) {
|
|
|
459
544
|
{err && !open && !newDraft && !switching && <div className="rb-switcher-err" role="alert">{err}</div>}
|
|
460
545
|
</div>
|
|
461
546
|
|
|
462
|
-
{/*
|
|
547
|
+
{/* Add-to-default confirm — the one modal in this surface. No 3-way merge UI.
|
|
548
|
+
After a GitHub-remote fold it flips to a pull-request result view (DDR-162). */}
|
|
463
549
|
{foldConfirm && (
|
|
464
|
-
<div className="rb-scrim" role="presentation" onClick={() => setFoldConfirm(false)}>
|
|
465
|
-
<div className="rb-sheet" role="dialog" aria-modal="true" aria-labelledby="rb-sheet-title" aria-describedby="rb-sheet-body" onClick={(e) => e.stopPropagation()} onKeyDown={(e) => { if (e.key === 'Escape') setFoldConfirm(false); }}>
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
550
|
+
<div className="rb-scrim" role="presentation" onClick={() => { setFoldConfirm(false); setPrResult(null); setPrCopied(false); }}>
|
|
551
|
+
<div className="rb-sheet" role="dialog" aria-modal="true" aria-labelledby="rb-sheet-title" aria-describedby="rb-sheet-body" onClick={(e) => e.stopPropagation()} onKeyDown={(e) => { if (e.key === 'Escape') { setFoldConfirm(false); setPrResult(null); setPrCopied(false); } }}>
|
|
552
|
+
{prResult ? (
|
|
553
|
+
prResult.url ? (
|
|
554
|
+
<>
|
|
555
|
+
<span className="rb-sheet-icon"><Icon name="share" size={20} /></span>
|
|
556
|
+
<h2 className="rb-sheet-title" id="rb-sheet-title">Pull request opened{prResult.number ? ` #${prResult.number}` : ''}</h2>
|
|
557
|
+
<p className="rb-sheet-body" id="rb-sheet-body">Your draft <b>“{branch}”</b> is up as a pull request into <b>{sharedName}</b>{prResult.repo ? <> of <b>{prResult.repo}</b></> : null}. Review and merge it on GitHub — that keeps your team's review rules.</p>
|
|
558
|
+
<p className="rb-sheet-meta rb-pr-url">{prResult.url}</p>
|
|
559
|
+
<div className="rb-sheet-actions">
|
|
560
|
+
<button type="button" className="btn btn--ghost" onClick={() => { setFoldConfirm(false); setPrResult(null); setPrCopied(false); }}>Close</button>
|
|
561
|
+
<button type="button" className="btn btn--primary" data-testid="switcher-pr-link" onClick={() => reviewPr(prResult.url)}><Icon name="share" size={15} /> {prCopied ? 'Link copied — paste in your browser' : 'Review on GitHub'}</button>
|
|
562
|
+
</div>
|
|
563
|
+
</>
|
|
564
|
+
) : (
|
|
565
|
+
<>
|
|
566
|
+
<span className="rb-sheet-icon"><Icon name="share" size={20} /></span>
|
|
567
|
+
<h2 className="rb-sheet-title" id="rb-sheet-title">Draft published</h2>
|
|
568
|
+
<p className="rb-sheet-body" id="rb-sheet-body">{prResult.message}</p>
|
|
569
|
+
<div className="rb-sheet-actions">
|
|
570
|
+
<button type="button" data-testid="switcher-pr-dismiss" className="btn btn--primary" onClick={() => { setFoldConfirm(false); setPrResult(null); setPrCopied(false); }}>Got it</button>
|
|
571
|
+
</div>
|
|
572
|
+
</>
|
|
573
|
+
)
|
|
574
|
+
) : (
|
|
575
|
+
<>
|
|
576
|
+
<span className="rb-sheet-icon"><Icon name="arrow-up-to-line" size={20} /></span>
|
|
577
|
+
<h2 className="rb-sheet-title" id="rb-sheet-title">Add this branch to {sharedName}</h2>
|
|
578
|
+
<p className="rb-sheet-body" id="rb-sheet-body">Propose everything in <b>“{currentDraft?.name || branch}”</b> to <b>{sharedName}</b> — the default branch everyone shares.</p>
|
|
579
|
+
<p className="rb-sheet-meta">On a shared GitHub project this opens a pull request for review; a local project merges directly. Nothing is lost — your work is kept in History.</p>
|
|
580
|
+
{err && <p className="rb-newdraft-err">{err}</p>}
|
|
581
|
+
<div className="rb-sheet-actions">
|
|
582
|
+
<button type="button" className="btn btn--ghost" onClick={() => { setFoldConfirm(false); setErr(''); }}>Cancel</button>
|
|
583
|
+
<button type="button" data-testid="switcher-merge-confirm" className="btn btn--primary" disabled={!!folding} onClick={foldDraft}><Icon name="arrow-up-to-line" size={15} /> {folding ? 'Adding…' : `Add to ${sharedName}`}</button>
|
|
584
|
+
</div>
|
|
585
|
+
</>
|
|
586
|
+
)}
|
|
475
587
|
</div>
|
|
476
588
|
</div>
|
|
477
589
|
)}
|