feat: improve cards
This commit is contained in:
@@ -38,7 +38,7 @@ function DialogOverlay({
|
||||
return (
|
||||
<DialogPrimitive.Overlay
|
||||
data-slot="dialog-overlay"
|
||||
className={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50", className)}
|
||||
className={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -62,7 +62,7 @@ export function Combobox({
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
className={cn("w-full justify-between", triggerClassName)}
|
||||
className={cn("w-full justify-between", !disabled && "cursor-pointer", triggerClassName)}
|
||||
disabled={disabled}
|
||||
>
|
||||
<div className="flex min-w-0 flex-1 items-center">
|
||||
|
||||
@@ -64,7 +64,7 @@ export function KanbanBoardGrid({
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className="grid gap-[3px] rounded-lg overflow-hidden h-full p-[2px]"
|
||||
className="grid gap-2 rounded-lg overflow-hidden h-full p-[2px]"
|
||||
style={{ gridTemplateColumns: `repeat(${columns.length}, minmax(0, 1fr))` }}
|
||||
>
|
||||
{columns.map((column) => (
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@kandev/ui/dropdown-menu';
|
||||
import { cn, extractRepoName } from '@/lib/utils';
|
||||
import { cn, getRepositoryDisplayName } from '@/lib/utils';
|
||||
|
||||
export interface Task {
|
||||
id: string;
|
||||
@@ -29,19 +29,42 @@ interface KanbanCardProps {
|
||||
onDelete?: (task: Task) => void;
|
||||
}
|
||||
|
||||
function KanbanCardBody({
|
||||
task,
|
||||
repoName,
|
||||
actions,
|
||||
}: {
|
||||
task: Task;
|
||||
repoName: string | null;
|
||||
actions?: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0 flex-1">
|
||||
{repoName && (
|
||||
<p className="text-[10px] mb-1 text-muted-foreground leading-tight truncate">{repoName}</p>
|
||||
)}
|
||||
<p className="text-sm font-medium leading-tight line-clamp-1">{task.title}</p>
|
||||
</div>
|
||||
{actions}
|
||||
</div>
|
||||
{task.description && (
|
||||
<p className="text-xs text-muted-foreground mt-1 leading-tight line-clamp-3">
|
||||
{task.description}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function KanbanCardLayout({ task, className }: KanbanCardProps & { className?: string }) {
|
||||
const repoName = extractRepoName(task.repositoryUrl);
|
||||
const repoName = getRepositoryDisplayName(task.repositoryUrl);
|
||||
|
||||
return (
|
||||
<Card size="sm" className={cn('w-full py-0', className)}>
|
||||
<CardContent className="px-2 py-1">
|
||||
{repoName && (
|
||||
<p className="text-xs text-muted-foreground leading-tight mb-1 truncate">{repoName}</p>
|
||||
)}
|
||||
<p className="text-sm font-medium leading-tight">{task.title}</p>
|
||||
{task.description && (
|
||||
<p className="text-xs text-muted-foreground mt-1 leading-tight">{task.description}</p>
|
||||
)}
|
||||
<KanbanCardBody task={task} repoName={repoName} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
@@ -52,7 +75,7 @@ export function KanbanCard({ task, onClick, onEdit, onDelete }: KanbanCardProps)
|
||||
id: task.id,
|
||||
});
|
||||
|
||||
const repoName = extractRepoName(task.repositoryUrl);
|
||||
const repoName = getRepositoryDisplayName(task.repositoryUrl);
|
||||
|
||||
const statusIcon = (() => {
|
||||
switch (task.state) {
|
||||
@@ -87,7 +110,7 @@ export function KanbanCard({ task, onClick, onEdit, onDelete }: KanbanCardProps)
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
className={cn(
|
||||
'cursor-pointer mb-2 w-full py-0 relative border border-border overflow-visible shadow-none ring-0',
|
||||
'max-h-48 rounded-sm data-[size=sm]:py-1 cursor-pointer mb-2 w-full py-0 relative border border-border overflow-visible shadow-none ring-0',
|
||||
task.state === 'IN_PROGRESS' && 'kanban-task-pulse',
|
||||
isDragging && 'opacity-50 z-50'
|
||||
)}
|
||||
@@ -96,48 +119,45 @@ export function KanbanCard({ task, onClick, onEdit, onDelete }: KanbanCardProps)
|
||||
{...attributes}
|
||||
>
|
||||
<CardContent className="px-2 py-1">
|
||||
{repoName && (
|
||||
<p className="text-xs text-muted-foreground leading-tight mb-1 truncate">{repoName}</p>
|
||||
)}
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<p className="text-sm font-medium leading-tight">{task.title}</p>
|
||||
<div className="flex items-center gap-2">
|
||||
{statusIcon}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="text-muted-foreground hover:text-foreground cursor-pointer"
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
onPointerDown={(event) => event.stopPropagation()}
|
||||
>
|
||||
<IconDots className="h-4 w-4" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
onEdit?.(task);
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
onDelete?.(task);
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
{task.description && (
|
||||
<p className="text-xs text-muted-foreground mt-1 leading-tight">{task.description}</p>
|
||||
)}
|
||||
<KanbanCardBody
|
||||
task={task}
|
||||
repoName={repoName}
|
||||
actions={
|
||||
<div className="flex items-center gap-2">
|
||||
{statusIcon}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="text-muted-foreground hover:text-foreground cursor-pointer"
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
onPointerDown={(event) => event.stopPropagation()}
|
||||
>
|
||||
<IconDots className="h-4 w-4" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
onEdit?.(task);
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
onDelete?.(task);
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -28,7 +28,7 @@ export function KanbanColumn({ column, tasks, onOpenTask, onEditTask, onDeleteTa
|
||||
<div
|
||||
ref={setNodeRef}
|
||||
className={cn(
|
||||
'flex flex-col h-full min-w-0 bg-card p-3 min-h-[600px] rounded-lg',
|
||||
'flex flex-col h-full min-w-0 p-4 min-h-[600px] rounded-sm border border-border',
|
||||
isOver && 'ring-2 ring-primary'
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -262,7 +262,7 @@ export function TaskCreateDialog({
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-none w-[900px] sm:!max-w-none max-h-[85vh] flex flex-col">
|
||||
<DialogContent className="max-w-none w-[900px] sm:!max-w-none max-h-[85vh] flex flex-col bg-card">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{submitLabel === 'Create' ? 'Create Task' : 'Edit Task'}</DialogTitle>
|
||||
</DialogHeader>
|
||||
@@ -292,9 +292,9 @@ export function TaskCreateDialog({
|
||||
{repositories.length === 0 && !repositoriesLoading ? (
|
||||
<div className="flex items-center justify-center h-10 px-3 py-2 text-sm border border-input rounded-md bg-background">
|
||||
<span className="text-muted-foreground mr-2">No repositories found.</span>
|
||||
<Link href="/settings/workspace" className="text-primary hover:underline">
|
||||
Add repository
|
||||
</Link>
|
||||
<Link href="/settings/workspace" className="text-primary hover:underline">
|
||||
Add repository
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<Combobox
|
||||
@@ -324,12 +324,13 @@ export function TaskCreateDialog({
|
||||
emptyMessage="No repository found."
|
||||
disabled={isEditMode || repositoriesLoading}
|
||||
dropdownLabel="Repository"
|
||||
className={isEditMode || repositoriesLoading ? undefined : 'cursor-pointer'}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<Combobox
|
||||
options={branches.map((branchObj) => {
|
||||
<Combobox
|
||||
options={branches.map((branchObj) => {
|
||||
const displayName = branchObj.type === 'remote' && branchObj.remote
|
||||
? `${branchObj.remote}/${branchObj.name}`
|
||||
: branchObj.name;
|
||||
@@ -362,12 +363,13 @@ export function TaskCreateDialog({
|
||||
searchPlaceholder="Search branches..."
|
||||
emptyMessage="No branch found."
|
||||
disabled={isEditMode || !repositoryId || branchesLoading}
|
||||
dropdownLabel="Branch"
|
||||
dropdownLabel="Base Branch"
|
||||
className={isEditMode || !repositoryId || branchesLoading ? undefined : 'cursor-pointer'}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{agentProfiles.length === 0 && !agentProfilesLoading ? (
|
||||
<div className="flex h-7 items-center justify-center gap-2 rounded-md border border-input bg-background px-3 text-sm text-muted-foreground">
|
||||
<div className="flex h-7 items-center justify-center gap-2 rounded-sm border border-input px-3 text-xs text-muted-foreground">
|
||||
<span>No agents found.</span>
|
||||
<Link href="/settings/agents" className="text-primary hover:underline">
|
||||
Add agent
|
||||
@@ -391,6 +393,7 @@ export function TaskCreateDialog({
|
||||
searchPlaceholder="Search agents..."
|
||||
emptyMessage="No agent found."
|
||||
dropdownLabel="Agent profile"
|
||||
className={agentProfilesLoading ? undefined : 'cursor-pointer'}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -401,7 +404,7 @@ export function TaskCreateDialog({
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setShowAdvancedSettings(!showAdvancedSettings)}
|
||||
className="text-muted-foreground"
|
||||
className="text-muted-foreground cursor-pointer"
|
||||
>
|
||||
<IconSettings className="h-4 w-4 mr-1" />
|
||||
{showAdvancedSettings ? 'Hide' : 'More Options'}
|
||||
@@ -486,7 +489,7 @@ export function TaskCreateDialog({
|
||||
</div>
|
||||
{startAgent && (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
A worktree will be created from this base branch.
|
||||
A git worktree will be created from the above branch.
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { formatUserHomePath, selectPreferredBranch, truncateRepoPath } from './utils';
|
||||
import {
|
||||
extractRepoName,
|
||||
formatUserHomePath,
|
||||
getRepositoryDisplayName,
|
||||
selectPreferredBranch,
|
||||
truncateRepoPath,
|
||||
} from './utils';
|
||||
|
||||
describe('formatUserHomePath', () => {
|
||||
it('replaces mac home path with tilde', () => {
|
||||
@@ -62,3 +68,27 @@ describe('selectPreferredBranch', () => {
|
||||
expect(selectPreferredBranch(branches)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('extractRepoName', () => {
|
||||
it('extracts org/name from ssh urls', () => {
|
||||
expect(extractRepoName('git@gitlab.com:org/repo.git')).toBe('org/repo');
|
||||
});
|
||||
|
||||
it('extracts org/name from https urls', () => {
|
||||
expect(extractRepoName('https://bitbucket.org/org/repo')).toBe('org/repo');
|
||||
});
|
||||
|
||||
it('returns null for local paths', () => {
|
||||
expect(extractRepoName('/Users/alex/Projects/App')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRepositoryDisplayName', () => {
|
||||
it('returns a tilde path for local repositories', () => {
|
||||
expect(getRepositoryDisplayName('/Users/alex/Projects/App')).toBe('~/Projects/App');
|
||||
});
|
||||
|
||||
it('returns org/name for remote repositories', () => {
|
||||
expect(getRepositoryDisplayName('https://github.com/org/repo.git')).toBe('org/repo');
|
||||
});
|
||||
});
|
||||
|
||||
+91
-75
@@ -2,7 +2,7 @@ import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -10,43 +10,59 @@ export function cn(...inputs: ClassValue[]) {
|
||||
* (e.g., HTTP on non-localhost where crypto.randomUUID is unavailable).
|
||||
*/
|
||||
export function generateUUID(): string {
|
||||
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
// Fallback implementation
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
||||
const r = (Math.random() * 16) | 0;
|
||||
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
});
|
||||
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
// Fallback implementation
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
||||
const r = (Math.random() * 16) | 0;
|
||||
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract organization/repository name from a repository URL or path.
|
||||
* Supports GitHub URLs and local paths.
|
||||
* Extract organization/repository name from a repository URL.
|
||||
* Supports common Git providers and SSH/HTTPS formats.
|
||||
* @param repositoryUrl - The repository URL or local path
|
||||
* @returns The org/repo-name format, or null if unable to extract
|
||||
*/
|
||||
export function extractRepoName(repositoryUrl: string | null | undefined): string | null {
|
||||
if (!repositoryUrl) return null;
|
||||
if (!repositoryUrl) return null;
|
||||
|
||||
try {
|
||||
// Try to parse as GitHub URL (https://github.com/org/repo or git@github.com:org/repo)
|
||||
const githubHttpMatch = repositoryUrl.match(/github\.com[:/]([^/]+\/[^/]+?)(\.git)?$/);
|
||||
if (githubHttpMatch) {
|
||||
return githubHttpMatch[1];
|
||||
try {
|
||||
const normalized = repositoryUrl.replace(/\.git$/, '');
|
||||
// SSH format: git@host:org/repo
|
||||
const sshMatch = normalized.match(/^[^@]+@[^:]+:([^/]+\/[^/]+)$/);
|
||||
if (sshMatch) {
|
||||
return sshMatch[1];
|
||||
}
|
||||
// HTTPS format: https://host/org/repo or http(s)://host/org/repo
|
||||
const httpMatch = normalized.match(/^https?:\/\/[^/]+\/([^/]+\/[^/]+)$/);
|
||||
if (httpMatch) {
|
||||
return httpMatch[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to extract from local path (e.g., /path/to/org/repo or ~/org/repo)
|
||||
const pathMatch = repositoryUrl.match(/([^/]+\/[^/]+)\/?$/);
|
||||
if (pathMatch) {
|
||||
return pathMatch[1];
|
||||
export function isLocalRepositoryPath(repositoryUrl: string): boolean {
|
||||
return (
|
||||
repositoryUrl.startsWith('/') ||
|
||||
repositoryUrl.startsWith('~/') ||
|
||||
/^[A-Za-z]:[\\/]/.test(repositoryUrl)
|
||||
);
|
||||
}
|
||||
|
||||
export function getRepositoryDisplayName(repositoryUrl: string | null | undefined): string | null {
|
||||
if (!repositoryUrl) return null;
|
||||
if (isLocalRepositoryPath(repositoryUrl)) {
|
||||
return formatUserHomePath(repositoryUrl.replace(/\.git$/, ''));
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
return extractRepoName(repositoryUrl) ?? repositoryUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,71 +70,71 @@ export function extractRepoName(repositoryUrl: string | null | undefined): strin
|
||||
* Supports macOS/Linux (/Users/name, /home/name) and Windows (C:\Users\name).
|
||||
*/
|
||||
export function formatUserHomePath(path: string): string {
|
||||
if (!path) return path;
|
||||
const normalized = path.replace(/\\/g, '/');
|
||||
const macMatch = normalized.match(/^\/Users\/[^/]+(\/.*)?$/);
|
||||
if (macMatch) {
|
||||
return `~${macMatch[1] ?? ''}`;
|
||||
}
|
||||
const linuxMatch = normalized.match(/^\/home\/[^/]+(\/.*)?$/);
|
||||
if (linuxMatch) {
|
||||
return `~${linuxMatch[1] ?? ''}`;
|
||||
}
|
||||
const windowsMatch = normalized.match(/^[A-Za-z]:\/Users\/[^/]+(\/.*)?$/);
|
||||
if (windowsMatch) {
|
||||
return `~${windowsMatch[1] ?? ''}`;
|
||||
}
|
||||
return path;
|
||||
if (!path) return path;
|
||||
const normalized = path.replace(/\\/g, '/');
|
||||
const macMatch = normalized.match(/^\/Users\/[^/]+(\/.*)?$/);
|
||||
if (macMatch) {
|
||||
return `~${macMatch[1] ?? ''}`;
|
||||
}
|
||||
const linuxMatch = normalized.match(/^\/home\/[^/]+(\/.*)?$/);
|
||||
if (linuxMatch) {
|
||||
return `~${linuxMatch[1] ?? ''}`;
|
||||
}
|
||||
const windowsMatch = normalized.match(/^[A-Za-z]:\/Users\/[^/]+(\/.*)?$/);
|
||||
if (windowsMatch) {
|
||||
return `~${windowsMatch[1] ?? ''}`;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate a repository path for display, favoring the last segments.
|
||||
*/
|
||||
export function truncateRepoPath(path: string, maxLength = 28): string {
|
||||
const displayPath = formatUserHomePath(path);
|
||||
if (displayPath.length <= maxLength) return displayPath;
|
||||
const normalizedPath = displayPath.replace(/\\/g, '/');
|
||||
const hasHomePrefix = normalizedPath.startsWith('~/');
|
||||
const hasRootPrefix = normalizedPath.startsWith('/');
|
||||
const prefix = hasHomePrefix ? '~/' : hasRootPrefix ? '/' : '';
|
||||
const parts = normalizedPath.replace(/^~\//, '').replace(/^\//, '').split('/').filter(Boolean);
|
||||
if (parts.length === 0) return displayPath;
|
||||
const lastTwo = parts.slice(-2).join('/');
|
||||
let result = `${prefix}.../${lastTwo}`;
|
||||
if (result.length <= maxLength) return result;
|
||||
const lastOne = parts.slice(-1).join('/');
|
||||
result = `${prefix}.../${lastOne}`;
|
||||
if (result.length <= maxLength) return result;
|
||||
const remaining = Math.max(1, maxLength - prefix.length - 4);
|
||||
return `${prefix}.../${lastOne.slice(-remaining)}`;
|
||||
const displayPath = formatUserHomePath(path);
|
||||
if (displayPath.length <= maxLength) return displayPath;
|
||||
const normalizedPath = displayPath.replace(/\\/g, '/');
|
||||
const hasHomePrefix = normalizedPath.startsWith('~/');
|
||||
const hasRootPrefix = normalizedPath.startsWith('/');
|
||||
const prefix = hasHomePrefix ? '~/' : hasRootPrefix ? '/' : '';
|
||||
const parts = normalizedPath.replace(/^~\//, '').replace(/^\//, '').split('/').filter(Boolean);
|
||||
if (parts.length === 0) return displayPath;
|
||||
const lastTwo = parts.slice(-2).join('/');
|
||||
let result = `${prefix}.../${lastTwo}`;
|
||||
if (result.length <= maxLength) return result;
|
||||
const lastOne = parts.slice(-1).join('/');
|
||||
result = `${prefix}.../${lastOne}`;
|
||||
if (result.length <= maxLength) return result;
|
||||
const remaining = Math.max(1, maxLength - prefix.length - 4);
|
||||
return `${prefix}.../${lastOne.slice(-remaining)}`;
|
||||
}
|
||||
|
||||
type BranchSelectionCandidate = {
|
||||
name: string;
|
||||
type?: string;
|
||||
remote?: string;
|
||||
name: string;
|
||||
type?: string;
|
||||
remote?: string;
|
||||
};
|
||||
|
||||
export function selectPreferredBranch(
|
||||
branches: BranchSelectionCandidate[]
|
||||
branches: BranchSelectionCandidate[]
|
||||
): string | null {
|
||||
const originMain = branches.find(
|
||||
(branch) => branch.type === 'remote' && branch.remote === 'origin' && branch.name === 'main'
|
||||
);
|
||||
if (originMain) return 'origin/main';
|
||||
const originMain = branches.find(
|
||||
(branch) => branch.type === 'remote' && branch.remote === 'origin' && branch.name === 'main'
|
||||
);
|
||||
if (originMain) return 'origin/main';
|
||||
|
||||
const originMaster = branches.find(
|
||||
(branch) => branch.type === 'remote' && branch.remote === 'origin' && branch.name === 'master'
|
||||
);
|
||||
if (originMaster) return 'origin/master';
|
||||
const originMaster = branches.find(
|
||||
(branch) => branch.type === 'remote' && branch.remote === 'origin' && branch.name === 'master'
|
||||
);
|
||||
if (originMaster) return 'origin/master';
|
||||
|
||||
const localMain = branches.find((branch) => branch.type === 'local' && branch.name === 'main');
|
||||
if (localMain) return 'main';
|
||||
const localMain = branches.find((branch) => branch.type === 'local' && branch.name === 'main');
|
||||
if (localMain) return 'main';
|
||||
|
||||
const localMaster = branches.find((branch) => branch.type === 'local' && branch.name === 'master');
|
||||
if (localMaster) return 'master';
|
||||
const localMaster = branches.find((branch) => branch.type === 'local' && branch.name === 'master');
|
||||
if (localMaster) return 'master';
|
||||
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
export const DEFAULT_LOCAL_ENVIRONMENT_KIND = 'local_pc';
|
||||
|
||||
Reference in New Issue
Block a user