mirror of
https://github.com/block/buzz.git
synced 2026-11-05 00:41:28 +00:00
## Summary - Makes Projects repository-aware across browsing, branch and tag selection, local and remote source management, work items, commits, and contextual repository actions. - Refines project details into consistent single-column reading surfaces with a resizable, section-aware context pod, while keeping project conversations available in the attached chat panel. - Adds persistent sidebar project navigation, direct entity links, repository discussion channels, contributor identity matching, and consistent loading and activity presentation. - Keeps branch-specific controls on code-oriented sections while Tasks, Reviews, and Channels remain repository-scoped, reducing misleading context and actions. Replacement for #5981 with an identical final tree flattened into one signed-off commit because the required DCO check suite remained stalled. ### Related issue N/A ### Testing - [x] Desktop pre-push checks, TypeScript typecheck, and unit tests - [x] E2E production build with `pnpm build:e2e` - [x] Focused Playwright smoke coverage for project workspace, task, review, commit, sidebar, and contextual-panel behavior - [ ] Attach final before/after screenshots after design review --------- Signed-off-by: Thomas Petersen <thomasp@squareup.com> Signed-off-by: Wintermute <165f0c871dd2586bb18b6aa109eeaf57bb2132ff4d27b10120f4368a0f627022@buzz.block.builderlab.xyz> Co-authored-by: Wintermute <165f0c871dd2586bb18b6aa109eeaf57bb2132ff4d27b10120f4368a0f627022@buzz.block.builderlab.xyz>
105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
import * as React from "react";
|
|
import { toast } from "sonner";
|
|
|
|
import type { Project, Repository } from "@/features/projects/hooks";
|
|
import { useCreateProjectIssueMutation } from "@/features/projects/issueMutations";
|
|
import { selectProjectRepository } from "@/features/projects/projectModels";
|
|
import {
|
|
CreateProjectWorkItemDialog,
|
|
type CreateProjectWorkItemDialogInput,
|
|
} from "./CreateProjectWorkItemDialog";
|
|
|
|
export function CreateProjectIssueDialog({
|
|
initialProjectId,
|
|
onCreated,
|
|
onOpenChange,
|
|
open,
|
|
projects,
|
|
}: {
|
|
initialProjectId?: string;
|
|
onCreated: (
|
|
project: Project,
|
|
repository: Repository,
|
|
issueId: string,
|
|
) => void | Promise<void>;
|
|
onOpenChange: (open: boolean) => void;
|
|
open: boolean;
|
|
projects: Project[];
|
|
}) {
|
|
const repositoryOptions = React.useMemo(
|
|
() =>
|
|
projects.flatMap((project) =>
|
|
project.repositories.map((repository) => ({ project, repository })),
|
|
),
|
|
[projects],
|
|
);
|
|
const initialProject =
|
|
projects.find((project) => project.id === initialProjectId) ?? projects[0];
|
|
const [repositoryId, setRepositoryId] = React.useState(
|
|
selectProjectRepository(initialProject, null)?.id ?? "",
|
|
);
|
|
const selection =
|
|
repositoryOptions.find(
|
|
(candidate) => candidate.repository.id === repositoryId,
|
|
) ?? repositoryOptions[0];
|
|
const project = selection?.project;
|
|
const repository = selection?.repository;
|
|
const createMutation = useCreateProjectIssueMutation(repository);
|
|
|
|
React.useEffect(() => {
|
|
if (!open) return;
|
|
const nextProject =
|
|
projects.find((candidate) => candidate.id === initialProjectId) ??
|
|
projects[0];
|
|
setRepositoryId(selectProjectRepository(nextProject, null)?.id ?? "");
|
|
}, [initialProjectId, open, projects]);
|
|
|
|
async function handleCreate(input: CreateProjectWorkItemDialogInput) {
|
|
if (!project || !repository) throw new Error("Choose a repository.");
|
|
const issueId = await createMutation.mutateAsync(input);
|
|
toast.success("Task created.");
|
|
await onCreated(project, repository, issueId);
|
|
}
|
|
|
|
return (
|
|
<CreateProjectWorkItemDialog
|
|
bodyPlaceholder="Add context, expected behavior, or reproduction steps"
|
|
description={
|
|
repository
|
|
? `Create a task in ${repository.name}`
|
|
: "Choose a repository for this task."
|
|
}
|
|
isCreating={createMutation.isPending}
|
|
itemName="issue"
|
|
onCreate={handleCreate}
|
|
onOpenChange={onOpenChange}
|
|
open={open}
|
|
submitDisabled={!repository}
|
|
title="Create a task"
|
|
titlePlaceholder="Describe the task"
|
|
>
|
|
<label className="block space-y-1.5 text-sm font-medium">
|
|
<span>Repository</span>
|
|
<select
|
|
className="h-10 w-full rounded-lg border border-input bg-background px-3 text-sm font-normal outline-hidden focus:ring-1 focus:ring-ring"
|
|
data-testid="create-issue-repository"
|
|
disabled={createMutation.isPending}
|
|
onChange={(event) => setRepositoryId(event.target.value)}
|
|
value={repository?.id ?? ""}
|
|
>
|
|
{repositoryOptions.map((candidate) => (
|
|
<option
|
|
key={candidate.repository.id}
|
|
value={candidate.repository.id}
|
|
>
|
|
{candidate.project.repositories.length > 1
|
|
? `${candidate.project.name} / ${candidate.repository.name}`
|
|
: candidate.project.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
</CreateProjectWorkItemDialog>
|
|
);
|
|
}
|