Add dashboard support for resolving task-branch PR conflicts with AI before PR creation. - add a dashboard PR conflict resolver that merges the selected base into the task branch, invokes an AI merge session on conflicted files, verifies markers are removed, then commits and pushes the updated branch - expose a POST /tasks/:id/pr/resolve-conflicts route plus client API/export wiring, docs updates, and a changeset for the published CLI package - update the Create PR modal UI, styling, and tests to surface preflight conflicts, trigger AI resolution, and refresh preflight state after success - add API coverage for successful and unresolved conflict-resolution paths and include the new route test in the dashboard API quality shard Files changed: .changeset/fn-5949-pr-conflict-resolution.md | 5 + docs/dashboard-guide.md | 1 + docs/task-management.md | 1 + packages/dashboard/README.md | 1 + packages/dashboard/app/api/legacy.ts | 20 ++ .../dashboard/app/components/PrCreateModal.css | 32 ++- .../dashboard/app/components/PrCreateModal.tsx | 46 ++++ .../components/__tests__/PrCreateModal.test.tsx | 33 +++ ...egister-git-github.pr-resolve-conflicts.test.ts | 186 +++++++++++++++ packages/dashboard/src/index.ts | 5 + packages/dashboard/src/pr-conflict-resolver.ts | 258 +++++++++++++++++++++ .../dashboard/src/routes/register-git-github.ts | 225 ++++++++++++------ packages/dashboard/vitest.config.ts | 2 +- 13 files changed, 739 insertions(+), 76 deletions(-) Fusion-Task-Id: FN-5949 Fusion-Task-Lineage: fea35fbf-6254-415c-83cc-0bc24abc911e
294 lines
6.0 KiB
CSS
294 lines
6.0 KiB
CSS
.pr-create-modal {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: min(calc(var(--space-2xl) * 20), 90vw);
|
|
height: min(80vh, calc(100dvh - var(--overlay-padding-top, 10vh) - var(--space-lg)));
|
|
min-width: min(calc(var(--space-2xl) * 15), 100vw);
|
|
min-height: calc(var(--space-2xl) * 12);
|
|
max-width: calc(100vw - var(--space-lg));
|
|
max-height: calc(100dvh - var(--overlay-padding-top, 10vh) - var(--space-lg));
|
|
resize: both;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.pr-create-modal__body {
|
|
display: flex;
|
|
flex: 1 1 auto;
|
|
flex-direction: column;
|
|
gap: var(--space-lg);
|
|
min-height: 0;
|
|
overflow-y: auto;
|
|
padding: var(--space-lg) var(--modal-padding);
|
|
}
|
|
|
|
.pr-create-modal__loading {
|
|
padding: var(--space-lg);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.pr-create-modal__section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-sm);
|
|
}
|
|
|
|
.pr-create-modal__section-title,
|
|
.pr-create-modal h4 {
|
|
margin: 0;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.pr-create-modal__preflight {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-sm);
|
|
}
|
|
|
|
.pr-create-modal__preflight-row {
|
|
display: grid;
|
|
grid-template-columns: auto auto 1fr;
|
|
align-items: start;
|
|
gap: var(--space-sm);
|
|
padding: var(--space-sm);
|
|
border: var(--btn-border-width) solid var(--border);
|
|
border-radius: var(--radius-md);
|
|
background: color-mix(in srgb, var(--surface) 90%, transparent);
|
|
}
|
|
|
|
.pr-create-modal__preflight-row.is-ok {
|
|
box-shadow: var(--glow-success);
|
|
}
|
|
|
|
.pr-create-modal__preflight-row.is-failed {
|
|
box-shadow: var(--glow-danger);
|
|
}
|
|
|
|
.pr-create-modal__preflight-label {
|
|
margin: 0;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.pr-create-modal__preflight-message {
|
|
margin: 0;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.pr-create-modal__title-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: var(--space-sm);
|
|
}
|
|
|
|
.pr-create-modal__conflict-resolution {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: var(--space-md);
|
|
padding: var(--space-md);
|
|
border: var(--btn-border-width) solid color-mix(in srgb, var(--color-warning) 35%, transparent);
|
|
background: color-mix(in srgb, var(--color-warning) 10%, transparent);
|
|
}
|
|
|
|
.pr-create-modal__conflict-copy {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-xs);
|
|
}
|
|
|
|
.pr-create-modal__conflict-title,
|
|
.pr-create-modal__conflict-message {
|
|
margin: 0;
|
|
}
|
|
|
|
.pr-create-modal__conflict-title {
|
|
font-weight: 600;
|
|
}
|
|
|
|
.pr-create-modal__conflict-message {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.pr-create-modal__label {
|
|
font-size: 0.75rem;
|
|
text-transform: uppercase;
|
|
color: var(--text-muted);
|
|
letter-spacing: 0.04em;
|
|
}
|
|
|
|
.pr-create-modal__inline-actions {
|
|
display: flex;
|
|
gap: var(--space-sm);
|
|
}
|
|
|
|
.pr-create-modal__body-input {
|
|
font-family: var(--font-mono);
|
|
min-height: calc(var(--space-2xl) * 4);
|
|
}
|
|
|
|
.pr-create-template-hint {
|
|
margin: 0;
|
|
color: var(--text-muted);
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.pr-create-modal__grid-two {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: var(--space-lg);
|
|
}
|
|
|
|
.pr-create-modal__draft {
|
|
align-self: end;
|
|
}
|
|
|
|
.pr-create-modal__chips {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--space-sm);
|
|
min-width: 0;
|
|
}
|
|
|
|
.pr-create-modal__chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: var(--space-xs);
|
|
min-width: 0;
|
|
padding: var(--space-xs) var(--space-sm);
|
|
border-radius: var(--radius-pill);
|
|
border: var(--btn-border-width) solid var(--border);
|
|
background: color-mix(in srgb, var(--card) 88%, transparent);
|
|
}
|
|
|
|
.pr-create-modal__chip-label {
|
|
min-width: 0;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.pr-create-modal__chip--colored {
|
|
background: color-mix(in srgb, var(--pr-chip-label-color, var(--card)) 25%, transparent);
|
|
}
|
|
|
|
.pr-create-modal__chip-remove {
|
|
min-width: 0;
|
|
min-height: 0;
|
|
width: auto;
|
|
height: auto;
|
|
padding: 0;
|
|
}
|
|
|
|
.pr-create-modal__option-list {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--space-sm);
|
|
min-width: 0;
|
|
}
|
|
|
|
.pr-create-modal__option-item {
|
|
text-align: left;
|
|
}
|
|
|
|
.pr-create-collapsible {
|
|
border: var(--btn-border-width) solid var(--border);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-sm);
|
|
}
|
|
|
|
.pr-create-collapsible summary {
|
|
cursor: pointer;
|
|
color: var(--text);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.pr-create-modal__preview {
|
|
margin-top: var(--space-sm);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-sm);
|
|
}
|
|
|
|
.pr-create-modal__commit-row,
|
|
.pr-create-modal__file-row {
|
|
display: grid;
|
|
grid-template-columns: 1fr auto auto;
|
|
gap: var(--space-sm);
|
|
align-items: center;
|
|
padding: var(--space-xs) 0;
|
|
border-bottom: var(--btn-border-width) solid color-mix(in srgb, var(--border) 70%, transparent);
|
|
}
|
|
|
|
.pr-create-modal__commit-row code {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.pr-create-modal__commit-row > *,
|
|
.pr-create-modal__file-row > * {
|
|
min-width: 0;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.pr-create-modal .form-error {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: var(--space-sm);
|
|
background: color-mix(in srgb, var(--color-error) 10%, transparent);
|
|
}
|
|
|
|
.pr-error {
|
|
background: color-mix(in srgb, var(--color-error) 10%, transparent);
|
|
border: var(--btn-border-width) solid color-mix(in srgb, var(--color-error) 35%, transparent);
|
|
border-radius: var(--radius-md);
|
|
}
|
|
|
|
.pr-error__hint {
|
|
margin: 0;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.pr-error__actions {
|
|
align-items: center;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--space-sm);
|
|
}
|
|
|
|
.pr-error__retry:focus-visible,
|
|
.pr-error__dismiss:focus-visible {
|
|
box-shadow: var(--focus-ring-strong);
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.pr-create-modal {
|
|
min-width: 0;
|
|
width: 100%;
|
|
height: auto;
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
resize: none;
|
|
}
|
|
|
|
.pr-create-modal__body {
|
|
gap: var(--space-md);
|
|
}
|
|
|
|
.pr-create-modal__title-row,
|
|
.pr-create-modal__grid-two,
|
|
.pr-create-modal__commit-row,
|
|
.pr-create-modal__file-row,
|
|
.pr-create-modal__conflict-resolution {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.pr-create-modal__draft {
|
|
align-self: start;
|
|
}
|
|
|
|
.pr-create-modal__inline-actions {
|
|
width: 100%;
|
|
flex-wrap: wrap;
|
|
}
|
|
}
|