Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Enforce LF line endings for all text files
* text=auto eol=lf

# Explicitly LF for source files
*.ts text eol=lf
*.tsx text eol=lf
*.js text eol=lf
*.jsx text eol=lf
*.json text eol=lf
*.md text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.css text eol=lf
*.mjs text eol=lf
51 changes: 51 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Build and Push Docker Image

on:
push:
branches:
- main
tags:
- 'v*'

permissions:
contents: read
packages: write

jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/kubeorch/ui
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=

- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
8 changes: 8 additions & 0 deletions app/dashboard/notifications/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ export default function NotificationsPage() {
{notifications.map(notification => (
<div
key={notification.id}
role="button"
tabIndex={0}
className={`flex items-start gap-3 rounded-lg border p-4 transition-colors cursor-pointer hover:bg-accent ${
!notification.read
? "border-primary/20 bg-primary/5"
Expand All @@ -104,6 +106,12 @@ export default function NotificationsPage() {
router.push(notification.link);
}
}}
onKeyDown={e => {
if (e.key === "Enter" || e.key === " ") {
if (!notification.read) markAsRead(notification.id);
if (notification.link) router.push(notification.link);
}
}}
>
<div className="mt-0.5">
{notificationIcon(notification.type)}
Expand Down
6 changes: 6 additions & 0 deletions app/dashboard/resources/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -700,10 +700,16 @@ export default function ResourceDetailPage() {
{pods.map(pod => (
<div
key={pod.id}
role="button"
tabIndex={0}
className="flex items-center justify-between rounded border p-3 cursor-pointer hover:bg-muted/50"
onClick={() =>
router.push(`/dashboard/resources/${pod.id}`)
}
onKeyDown={e => {
if (e.key === "Enter" || e.key === " ")
router.push(`/dashboard/resources/${pod.id}`);
}}
>
<div className="flex items-center gap-3">
<Box className="h-4 w-4 text-muted-foreground" />
Expand Down
6 changes: 3 additions & 3 deletions app/dashboard/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export default function SettingsPage() {
{isAdmin ? (
<>
<div className="space-y-2">
<label className="text-sm font-medium">Invite Link</label>
<span className="text-sm font-medium">Invite Link</span>
<div className="p-3 bg-muted rounded-lg">
<code className="text-xs break-all">
{getInviteLink(inviteCode || "XXXXXX")}
Expand All @@ -124,10 +124,10 @@ export default function SettingsPage() {

<div className="flex items-center justify-between p-3 rounded-lg border">
<div className="space-y-0.5">
<label className="text-sm font-medium flex items-center gap-2">
<span className="text-sm font-medium flex items-center gap-2">
<RefreshCw className="h-4 w-4" />
Regenerate code after signup
</label>
</span>
<p className="text-xs text-muted-foreground">
Automatically generate a new invite code after each
user signs up
Expand Down
6 changes: 6 additions & 0 deletions app/dashboard/workflow/new/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@
setPendingSourceName("");
setIsAnalyzing(false);
}
}, [asyncSessionId, importSession?.status, asyncAnalysis, pendingSourceName]);

Check warning on line 171 in app/dashboard/workflow/new/page.tsx

View workflow job for this annotation

GitHub Actions / build (20)

React Hook useEffect has a missing dependency: 'importSession.errorMessage'. Either include it or remove the dependency array

// Handle stream errors
useEffect(() => {
Expand Down Expand Up @@ -760,6 +760,8 @@
<div className="space-y-3">
{/* File Upload - Full width */}
<div
role="button"
tabIndex={0}
className={`
border rounded-lg p-4 text-center cursor-pointer transition-colors
${
Expand All @@ -776,6 +778,10 @@
onClick={() =>
document.getElementById("file-input")?.click()
}
onKeyDown={e => {
if (e.key === "Enter" || e.key === " ")
document.getElementById("file-input")?.click();
}}
>
<input
id="file-input"
Expand Down
15 changes: 5 additions & 10 deletions components/auth/ProviderIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import {
Github,
KeyRound,
Lock,
Shield,
Globe,
type LucideProps,
} from "lucide-react";
import { KeyRound, Lock, Shield, Globe, type LucideProps } from "lucide-react";
import { GithubIcon } from "@/components/ui/github-icon";

const iconMap: Record<string, React.FC<LucideProps>> = {
github: Github,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const iconMap: Record<string, React.FC<any>> = {
github: GithubIcon,
lock: Lock,
shield: Shield,
globe: Globe,
Expand Down
5 changes: 5 additions & 0 deletions components/layout/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,13 @@ export function TopBar({ onOpenCommandPalette }: TopBarProps) {
<header className="sticky top-0 z-40 flex items-center justify-between border-b border-border bg-background px-6 py-[14px]">
<div className="flex flex-1 items-center gap-4">
<div
role="button"
tabIndex={0}
className="relative max-w-md flex-1 cursor-pointer"
onClick={onOpenCommandPalette}
onKeyDown={e => {
if (e.key === "Enter" || e.key === " ") onOpenCommandPalette?.();
}}
>
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<Input
Expand Down
4 changes: 4 additions & 0 deletions components/ui/ResizablePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export function ResizablePanel({
>
{/* Resize Handle */}
<div
role="slider"
aria-orientation="vertical"
aria-valuenow={0}
tabIndex={0}
onMouseDown={handleMouseDown}
className={`absolute left-0 top-0 h-full w-1 cursor-col-resize hover:bg-primary transition-colors ${
isResizing ? "bg-primary" : "bg-transparent"
Expand Down
11 changes: 9 additions & 2 deletions components/ui/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,23 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
);
}

function CardTitle({ className, ...props }: React.ComponentProps<"h3">) {
function CardTitle({
className,
children,
...props
}: React.ComponentProps<"h3">) {
return (
// eslint-disable-next-line jsx-a11y/heading-has-content -- children are always passed by consumers
<h3
data-slot="card-title"
className={cn(
"text-2xl font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
>
{children}
</h3>
);
}

Expand Down
11 changes: 9 additions & 2 deletions components/ui/compact-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,20 @@ function CompactCardHeader({
);
}

function CompactCardTitle({ className, ...props }: React.ComponentProps<"h3">) {
function CompactCardTitle({
className,
children,
...props
}: React.ComponentProps<"h3">) {
return (
// eslint-disable-next-line jsx-a11y/heading-has-content -- children are always passed by consumers
<h3
data-slot="compact-card-title"
className={cn("text-sm leading-none font-semibold", className)}
{...props}
/>
>
{children}
</h3>
);
}

Expand Down
22 changes: 22 additions & 0 deletions components/ui/github-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { SVGProps } from "react";

export function GithubIcon({
className,
size = 24,
...props
}: SVGProps<SVGSVGElement> & { size?: number }) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 50 50"
width={size}
height={size}
fill="currentColor"
className={className}
aria-hidden="true"
{...props}
>
<path d="M17.791 46.836C18.502 46.53 19 45.823 19 45v-5.4c0-.197.016-.402.041-.61C19.027 38.994 19.014 38.997 19 39c0 0-3 0-3.6 0-1.5 0-2.8-.6-3.4-1.8-.7-1.3-1-3.5-2.8-4.7C8.9 32.3 9.1 32 9.7 32c.6.1 1.9.9 2.7 2 .9 1.1 1.8 2 3.4 2 2.487 0 3.82-.125 4.622-.555C21.356 34.056 22.649 33 24 33v-.025c-5.668-.182-9.289-2.066-10.975-4.975-3.665.042-6.856.405-8.677.707a18.87 18.87 0 0 1-.151-.987c1.797-.296 4.843-.647 8.345-.714a12.46 12.46 0 0 1-.291-.849c-3.511-.178-6.541-.039-8.187.097-.02-.332-.047-.663-.051-.999 1.649-.135 4.597-.27 8.018-.111a12.29 12.29 0 0 1-.13-1.543c0-1.7.6-3.5 1.7-5-.5-1.7-1.2-5.3.2-6.6 2.7 0 4.6 1.3 5.5 2.1C21 13.4 22.9 13 25 13s4 .4 5.6 1.1c.9-.8 2.8-2.1 5.5-2.1 1.5 1.4.7 5 .2 6.6 1.1 1.5 1.7 3.2 1.6 5 0 .484-.045.951-.11 1.409 3.499-.172 6.527-.034 8.204.102-.002.337-.033.666-.051.999-1.671-.138-4.775-.28-8.359-.089a12.44 12.44 0 0 1-.325.98c3.546.046 6.665.389 8.548.689a18.87 18.87 0 0 1-.151.987c-1.912-.306-5.171-.664-8.879-.682C35.112 30.873 31.557 32.75 26 32.969V33c2.6 0 5 3.9 5 6.6V45c0 .823.498 1.53 1.209 1.836C41.37 43.804 48 35.164 48 25 48 12.318 37.683 2 25 2S2 12.318 2 25c0 10.164 6.63 18.804 15.791 21.836z" />
</svg>
);
}
1 change: 1 addition & 0 deletions components/workflow/CommandPalette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@

window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [isOpen, filteredTemplates, selectedIndex, onClose]);

Check warning on line 453 in components/workflow/CommandPalette.tsx

View workflow job for this annotation

GitHub Actions / build (20)

React Hook useEffect has a missing dependency: 'handleSelectTemplate'. Either include it or remove the dependency array

// Reset selected index when filtered results change
useEffect(() => {
Expand Down Expand Up @@ -501,6 +501,7 @@
value={searchQuery}
onChange={e => setSearchQuery(e.target.value)}
className="pl-9 pr-9"
// eslint-disable-next-line jsx-a11y/no-autofocus -- intentional: command palette search should be focused immediately on open
autoFocus
/>
{searchQuery && (
Expand Down
6 changes: 6 additions & 0 deletions components/workflow/ImportDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ export function ImportDialog({ isOpen, onClose, onImport }: ImportDialogProps) {

{/* File Upload */}
<div
role="button"
tabIndex={0}
className={`
border rounded-lg p-4 text-center cursor-pointer transition-colors
${
Expand All @@ -309,6 +311,10 @@ export function ImportDialog({ isOpen, onClose, onImport }: ImportDialogProps) {
onClick={() =>
document.getElementById("import-file-input")?.click()
}
onKeyDown={e => {
if (e.key === "Enter" || e.key === " ")
document.getElementById("import-file-input")?.click();
}}
>
<input
id="import-file-input"
Expand Down
12 changes: 9 additions & 3 deletions components/workflow/import/ImportDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import {
} from "@/components/ui/collapsible";
import {
Upload,
Github,
GitBranch,
Link,
Loader2,
Expand All @@ -38,6 +37,7 @@ import {
ChevronUp,
Terminal,
} from "lucide-react";
import { GithubIcon } from "@/components/ui/github-icon";
import { toast } from "sonner";
import {
ImportAnalysis,
Expand Down Expand Up @@ -293,7 +293,7 @@ export function ImportDialog({
File Upload
</TabsTrigger>
<TabsTrigger value="url" className="flex items-center gap-2">
<Github className="h-4 w-4" />
<GithubIcon className="h-4 w-4" />
Git URL
</TabsTrigger>
</TabsList>
Expand All @@ -318,6 +318,8 @@ export function ImportDialog({
<TabsContent value="file" className="mt-0 space-y-4">
{/* Drag and drop zone */}
<div
role="button"
tabIndex={0}
className={`
relative border-2 border-dashed rounded-lg p-8 text-center
transition-colors cursor-pointer
Expand All @@ -332,6 +334,10 @@ export function ImportDialog({
onDragOver={handleDrag}
onDrop={handleDrop}
onClick={() => document.getElementById("file-input")?.click()}
onKeyDown={e => {
if (e.key === "Enter" || e.key === " ")
document.getElementById("file-input")?.click();
}}
>
<input
id="file-input"
Expand Down Expand Up @@ -426,7 +432,7 @@ export function ImportDialog({
</>
) : (
<>
<Github className="mr-2 h-4 w-4" />
<GithubIcon className="mr-2 h-4 w-4" />
Analyze Repository
</>
)}
Expand Down
17 changes: 3 additions & 14 deletions lib/utils/__tests__/errorReporter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,14 @@ describe("errorReporter", () => {
const error = new Error("test error");
errorReporter.report(error);

expect(console.error).toHaveBeenCalledWith(
"[ErrorReporter]",
error,
""
);
expect(console.error).toHaveBeenCalledWith("[ErrorReporter]", error, "");
});

it("should include source in log label", () => {
const error = new Error("test error");
errorReporter.report(error, { source: "TestComponent" });

expect(console.error).toHaveBeenCalledWith(
"[TestComponent]",
error,
""
);
expect(console.error).toHaveBeenCalledWith("[TestComponent]", error, "");
});

it("should include metadata in log", () => {
Expand Down Expand Up @@ -97,10 +89,7 @@ describe("errorReporter", () => {

errorReporter.initGlobalHandlers();

expect(addEventSpy).toHaveBeenCalledWith(
"error",
expect.any(Function)
);
expect(addEventSpy).toHaveBeenCalledWith("error", expect.any(Function));
expect(addEventSpy).toHaveBeenCalledWith(
"unhandledrejection",
expect.any(Function)
Expand Down
Loading
Loading