Merge public-gh/master into paperclip-company-import-export
This commit is contained in:
@@ -75,11 +75,15 @@ export function CommandPalette() {
|
||||
enabled: !!selectedCompanyId && open,
|
||||
});
|
||||
|
||||
const { data: projects = [] } = useQuery({
|
||||
const { data: allProjects = [] } = useQuery({
|
||||
queryKey: queryKeys.projects.list(selectedCompanyId!),
|
||||
queryFn: () => projectsApi.list(selectedCompanyId!),
|
||||
enabled: !!selectedCompanyId && open,
|
||||
});
|
||||
const projects = useMemo(
|
||||
() => allProjects.filter((p) => !p.archivedAt),
|
||||
[allProjects],
|
||||
);
|
||||
|
||||
function go(path: string) {
|
||||
setOpen(false);
|
||||
|
||||
@@ -131,8 +131,12 @@ export function IssueProperties({ issue, onUpdate, inline }: IssuePropertiesProp
|
||||
queryFn: () => projectsApi.list(companyId!),
|
||||
enabled: !!companyId,
|
||||
});
|
||||
const activeProjects = useMemo(
|
||||
() => (projects ?? []).filter((p) => !p.archivedAt || p.id === issue.projectId),
|
||||
[projects, issue.projectId],
|
||||
);
|
||||
const { orderedProjects } = useProjectOrder({
|
||||
projects: projects ?? [],
|
||||
projects: activeProjects,
|
||||
companyId,
|
||||
userId: currentUserId,
|
||||
});
|
||||
|
||||
@@ -117,7 +117,7 @@ export function MarkdownBody({ children, className }: MarkdownBodyProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"paperclip-markdown prose prose-sm max-w-none break-words overflow-hidden prose-pre:whitespace-pre-wrap prose-pre:break-words prose-code:break-all",
|
||||
"paperclip-markdown prose prose-sm max-w-none break-words overflow-hidden",
|
||||
theme === "dark" && "prose-invert",
|
||||
className,
|
||||
)}
|
||||
|
||||
@@ -288,8 +288,12 @@ export function NewIssueDialog() {
|
||||
queryFn: () => authApi.getSession(),
|
||||
});
|
||||
const currentUserId = session?.user?.id ?? session?.session?.userId ?? null;
|
||||
const activeProjects = useMemo(
|
||||
() => (projects ?? []).filter((p) => !p.archivedAt),
|
||||
[projects],
|
||||
);
|
||||
const { orderedProjects } = useProjectOrder({
|
||||
projects: projects ?? [],
|
||||
projects: activeProjects,
|
||||
companyId: effectiveCompanyId,
|
||||
userId: currentUserId,
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Separator } from "@/components/ui/separator";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { AlertCircle, Check, ExternalLink, Github, Loader2, Plus, Trash2, X } from "lucide-react";
|
||||
import { AlertCircle, Archive, ArchiveRestore, Check, ExternalLink, Github, Loader2, Plus, Trash2, X } from "lucide-react";
|
||||
import { ChoosePathButton } from "./PathInstructionsModal";
|
||||
import { DraftInput } from "./agent-config-primitives";
|
||||
import { InlineEditor } from "./InlineEditor";
|
||||
@@ -34,6 +34,8 @@ interface ProjectPropertiesProps {
|
||||
onUpdate?: (data: Record<string, unknown>) => void;
|
||||
onFieldUpdate?: (field: ProjectConfigFieldKey, data: Record<string, unknown>) => void;
|
||||
getFieldSaveState?: (field: ProjectConfigFieldKey) => ProjectFieldSaveState;
|
||||
onArchive?: (archived: boolean) => void;
|
||||
archivePending?: boolean;
|
||||
}
|
||||
|
||||
export type ProjectFieldSaveState = "idle" | "saving" | "saved" | "error";
|
||||
@@ -152,7 +154,7 @@ function ProjectStatusPicker({ status, onChange }: { status: string; onChange: (
|
||||
);
|
||||
}
|
||||
|
||||
export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSaveState }: ProjectPropertiesProps) {
|
||||
export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSaveState, onArchive, archivePending }: ProjectPropertiesProps) {
|
||||
const { selectedCompanyId } = useCompany();
|
||||
const queryClient = useQueryClient();
|
||||
const [goalOpen, setGoalOpen] = useState(false);
|
||||
@@ -954,6 +956,45 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
{onArchive && (
|
||||
<>
|
||||
<Separator className="my-4" />
|
||||
<div className="space-y-4 py-4">
|
||||
<div className="text-xs font-medium text-destructive uppercase tracking-wide">
|
||||
Danger Zone
|
||||
</div>
|
||||
<div className="space-y-3 rounded-md border border-destructive/40 bg-destructive/5 px-4 py-4">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{project.archivedAt
|
||||
? "Unarchive this project to restore it in the sidebar and project selectors."
|
||||
: "Archive this project to hide it from the sidebar and project selectors."}
|
||||
</p>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
disabled={archivePending}
|
||||
onClick={() => {
|
||||
const action = project.archivedAt ? "Unarchive" : "Archive";
|
||||
const confirmed = window.confirm(
|
||||
`${action} project "${project.name}"?`,
|
||||
);
|
||||
if (!confirmed) return;
|
||||
onArchive(!project.archivedAt);
|
||||
}}
|
||||
>
|
||||
{archivePending ? (
|
||||
<><Loader2 className="h-3 w-3 animate-spin mr-1" />{project.archivedAt ? "Unarchiving..." : "Archiving..."}</>
|
||||
) : project.archivedAt ? (
|
||||
<><ArchiveRestore className="h-3 w-3 mr-1" />Unarchive project</>
|
||||
) : (
|
||||
<><Archive className="h-3 w-3 mr-1" />Archive project</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user