refactor(renderer): route all Phosphor icon imports through ui/icons barrel

Create src/renderer/components/ui/icons.ts as the single re-export point
for every Phosphor icon the renderer touches, then rewrite the 95 files
that previously imported directly from "@phosphor-icons/react" to pull
from the relative-path-to-barrel instead. The TitleBar commit earlier
in this series already used ui/icons; this commit extends the pattern
to the rest of the renderer.

Benefits now wired in:
  - one location where bundle tree-shaking can be reasoned about,
  - typos like Briefcase vs BriefCase show up against a finite list,
  - re-theming or swapping icon sets is a one-file edit,
  - a lint rule that flags raw @phosphor-icons/react imports can be
    added later without mass-rewriting call sites.

The barrel also re-exports the `Icon` type so call sites that type
icon props against the Phosphor component type work unchanged.

Test count stays at 363 passing; typecheck stays at 156 errors.
This commit is contained in:
ZacharyZhang-NY committed 2026-04-16 23:37:35 -04:00
1 parent 364f1683e3
commit 75022f82c5
95 files changed
+424 -94

No files matched your search

+1 -1
View File
@@ -1,5 +1,5 @@
import { useCallback, useMemo, type ReactNode } from "react";
import { CircleNotch, TerminalWindow } from "@phosphor-icons/react";
import { CircleNotch, TerminalWindow } from "./components/ui/icons";
import { LocaleContext, TranslationContext, type TranslationFn } from "./i18n";
import type { AppLocale } from "@shared/locale";
import { CompanyOnboarding } from "./components/CompanyOnboarding";
+1 -1
View File
@@ -1,5 +1,5 @@
import { useState, useEffect, useCallback } from "react";
import { Copy, Minus, Square, X } from "@phosphor-icons/react";
import { Copy, Minus, Square, X } from "./ui/icons";
export default function TitleBar() {
const [maximized, setMaximized] = useState(false);
+1 -1
View File
@@ -1,5 +1,5 @@
import { AnimatePresence, motion } from "framer-motion"
import { CheckCircle, Warning, X, XCircle } from "@phosphor-icons/react"
import { CheckCircle, Warning, X, XCircle } from "./ui/icons"
import { useAppStore } from "../state/store"
import { useReducedMotion } from "./ui"
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useState } from "react"
import { AnimatePresence, motion } from "framer-motion"
import { ArrowRight, ArrowsClockwise, Lightning, Plus, Robot, X } from "@phosphor-icons/react"
import { ArrowRight, ArrowsClockwise, Lightning, Plus, Robot, X } from "../ui/icons"
import type { AutomationAction, AutomationRuleRecord, AutomationStatus, AutomationTrigger, WorkflowPipelineRecord } from "@shared/types"
import { ActionButton, ConfirmDialog } from "../ui"
import { useT } from "../../i18n"
@@ -1,5 +1,5 @@
import { motion } from "framer-motion"
import { ArrowRight, CaretRight, Gear, Lightning, Pause, Play, Trash } from "@phosphor-icons/react"
import { ArrowRight, CaretRight, Gear, Lightning, Pause, Play, Trash } from "../ui/icons"
import type { AutomationRuleRecord } from "@shared/types"
import { timeAgo } from "../../lib/formatters"
import { triggerConfig, actionConfig, statusColors } from "./automation-config"
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from "react"
import { Gear, Lightning } from "@phosphor-icons/react"
import { Gear, Lightning } from "../ui/icons"
import type { AutomationAction, AutomationRuleRecord, AutomationTrigger, DepartmentId } from "@shared/types"
import { ActionButton, Modal, Select } from "../ui"
import { triggerConfig, actionConfig, departmentOptions, safeJsonStringify } from "./automation-config"
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from "react"
import { ArrowsClockwise, Gear } from "@phosphor-icons/react"
import { ArrowsClockwise, Gear } from "../ui/icons"
import type { AutomationTrigger, WorkflowPipelineRecord, WorkflowStatus } from "@shared/types"
import { ActionButton, Modal, Select } from "../ui"
import { triggerConfig, safeJsonStringify } from "./automation-config"
@@ -1,6 +1,6 @@
import { useMemo, useState } from "react"
import { AnimatePresence, motion } from "framer-motion"
import { ArrowsClockwise, CaretRight, Gear, Lightning, Play, Trash } from "@phosphor-icons/react"
import { ArrowsClockwise, CaretRight, Gear, Lightning, Play, Trash } from "../ui/icons"
import type { WorkflowPipelineRecord, WorkflowStep } from "@shared/types"
import { timeAgo } from "../../lib/formatters"
import { triggerConfig, actionConfig, workflowStatusColors, stepStatusConfig, safeJsonParse } from "./automation-config"
@@ -1,5 +1,5 @@
import type { AutomationAction, AutomationStatus, AutomationTrigger, WorkflowStatus, WorkflowStep } from "@shared/types"
import { ArrowsClockwise, Eye, Funnel, Lightning, Pause, Play, Plus, Robot, Timer, Trash } from "@phosphor-icons/react"
import { ArrowsClockwise, Eye, Funnel, Lightning, Pause, Play, Plus, Robot, Timer, Trash } from "../ui/icons"
import { DEPARTMENT_OPTIONS } from "@shared/constants"
export const triggerConfig: Record<AutomationTrigger, { label: string; description: string; icon: typeof Lightning }> = {
@@ -1,5 +1,5 @@
import type { AgentMessageRecord, CommentRecord, TaskRecord, MessageChannel } from "@shared/types"
import { CaretDown } from "@phosphor-icons/react"
import { CaretDown } from "../ui/icons"
import { useT } from "../../i18n"
export interface ChannelDescriptor {
@@ -1,6 +1,6 @@
import { useState } from "react"
import { AnimatePresence, motion } from "framer-motion"
import { EnvelopeSimple, Hash, Buildings, Megaphone, Fire, MagnifyingGlass, Funnel } from "@phosphor-icons/react"
import { EnvelopeSimple, Hash, Buildings, Megaphone, Fire, MagnifyingGlass, Funnel } from "../ui/icons"
import type { AgentRecord, MessageChannel } from "@shared/types"
import { AgentAvatar } from "./MessageItem"
import type { ChannelDescriptor, TaskDiscussionDescriptor } from "./ChannelHeader"
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { AnimatePresence, motion } from "framer-motion"
import { ArrowBendUpLeft, X, ChatCircle, UserCircle, Paperclip, FileText } from "@phosphor-icons/react"
import { ArrowBendUpLeft, X, ChatCircle, UserCircle, Paperclip, FileText } from "../ui/icons"
import type { AgentMessageRecord, AgentRecord, DocumentRecord, MessageChannel } from "@shared/types"
import { unwrap } from "../../lib/desktop"
import { cmdOrCtrlLabel } from "../../lib/platform"
@@ -8,7 +8,7 @@ import {
WarningCircle,
ArrowBendUpLeft,
UserCircle,
} from "@phosphor-icons/react"
} from "../ui/icons"
import type { AgentMessageRecord, AgentRecord, CommentRecord, DepartmentId } from "@shared/types"
import { getAgentInitials, formatMessageTime } from "../../lib/formatters"
import { safeJson } from "../../lib/safe-json"
@@ -1,6 +1,6 @@
import { useRef, useEffect, useMemo } from "react"
import { useVirtualizer } from "@tanstack/react-virtual"
import { ChatCircle, Tray } from "@phosphor-icons/react"
import { ChatCircle, Tray } from "../ui/icons"
import type { AgentMessageRecord, AgentRecord, CommentRecord, TaskRecord } from "@shared/types"
import { MessageBubble, TaskCommentBubble } from "./MessageItem"
import type { AnyChannel } from "./ChannelHeader"
@@ -1,7 +1,7 @@
import { useRef, useCallback } from "react"
import { useVirtualizer } from "@tanstack/react-virtual"
import { motion } from "framer-motion"
import { EnvelopeSimple, Buildings, Megaphone, Hash, Fire } from "@phosphor-icons/react"
import { EnvelopeSimple, Buildings, Megaphone, Hash, Fire } from "../ui/icons"
import type { AgentMessageRecord, AgentRecord, MessageChannel } from "@shared/types"
import { AgentAvatar } from "./MessageItem"
import { formatMessageTime } from "../../lib/formatters"
@@ -7,7 +7,7 @@
*/
import { useState, useEffect, useCallback, useRef } from "react"
import { X, ChatCircleDots, ArrowBendUpLeft } from "@phosphor-icons/react"
import { X, ChatCircleDots, ArrowBendUpLeft } from "../ui/icons"
import { motion } from "framer-motion"
import type { AgentRecord, ConversationEventRecord, ThreadWaitStateRecord, ConversationThreadRecord, DocumentRecord } from "@shared/types"
import WaitStateIndicator, { type WaitStateInfo } from "./WaitStateIndicator"
@@ -6,7 +6,7 @@
* Provides a primary action button to reply or navigate to the approval.
*/
import { Hourglass, ChatCircle, CheckCircle } from "@phosphor-icons/react"
import { Hourglass, ChatCircle, CheckCircle } from "../ui/icons"
import type { AgentRecord } from "@shared/types"
export interface WaitStateInfo {
@@ -1,5 +1,5 @@
import { forwardRef, useCallback, type ReactNode, type KeyboardEvent, type ChangeEvent } from "react";
import { PaperPlaneTilt } from "@phosphor-icons/react";
import { PaperPlaneTilt } from "../../ui/icons";
import { ActionButton, InlineNotice } from "../../ui";
export interface ComposerShellProps {
@@ -1,4 +1,4 @@
import { Buildings, FolderOpen } from "@phosphor-icons/react";
import { Buildings, FolderOpen } from "../ui/icons";
import type { ConnectorId } from "@shared/types";
import { ActionButton, Input, TextArea, Select } from "../ui";
import { OnboardingStep } from "./OnboardingStep";
@@ -1,4 +1,4 @@
import { ArrowRight, Brain, UserCircle, type Icon } from "@phosphor-icons/react";
import { ArrowRight, Brain, UserCircle, type Icon } from "../ui/icons";
import { OnboardingStep } from "./OnboardingStep";
import { useOnboarding } from "./OnboardingContext";
@@ -1,5 +1,5 @@
import { motion } from "framer-motion";
import { CheckCircle, Rocket } from "@phosphor-icons/react";
import { CheckCircle, Rocket } from "../ui/icons";
import { ActionButton } from "../ui";
import { useOnboarding } from "./OnboardingContext";
@@ -1,5 +1,5 @@
import { motion } from "framer-motion";
import { Cpu, Lightning } from "@phosphor-icons/react";
import { Cpu, Lightning } from "../ui/icons";
import { ActionButton, Input, TextArea } from "../ui";
import { getStepNumber, TOTAL_STEPS } from "./OnboardingHero";
import { useOnboarding } from "./OnboardingContext";
@@ -4,7 +4,7 @@ import {
ArrowRight,
ArrowCounterClockwise,
Terminal,
} from "@phosphor-icons/react";
} from "../ui/icons";
import { ActionButton } from "../ui";
import type { TerminalCommandKey } from "@shared/contracts";
import { OnboardingStep } from "./OnboardingStep";
@@ -7,7 +7,7 @@ import {
Rocket,
SlidersHorizontal,
Target,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { AppLocale } from "@shared/locale";
export type OnboardingStep =
@@ -1,5 +1,5 @@
import { useState } from "react";
import { ArrowRight, FloppyDisk, SignIn } from "@phosphor-icons/react";
import { ArrowRight, FloppyDisk, SignIn } from "../ui/icons";
import { ActionButton } from "../ui";
import {
CompatProviderCard,
@@ -5,7 +5,7 @@ import {
CaretRight,
FloppyDisk,
Terminal,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { ProfileSnapshot } from "@shared/types";
import type { TerminalCommandKey } from "@shared/contracts";
@@ -1,5 +1,5 @@
import { motion } from "framer-motion";
import { GlobeSimple, Rocket } from "@phosphor-icons/react";
import { GlobeSimple, Rocket } from "../ui/icons";
import type { AppLocale } from "@shared/locale";
import { APP_LOCALES, LOCALE_LABELS } from "@shared/locale";
import { ActionButton } from "../ui";
@@ -1,5 +1,5 @@
import { useMemo, useState } from "react";
import { FileText, FloppyDisk, NotePencil, Trash } from "@phosphor-icons/react";
import { FileText, FloppyDisk, NotePencil, Trash } from "../ui/icons";
import type { AgentRecord, DocumentRecord, GoalRecord, ProjectRecord } from "@shared/types";
import { ActionButton, ConfirmDialog, InlineNotice, Input, ListFrame, ListRow, Modal, Select, StatusPill, TextArea } from "../ui";
import { useT } from "../../i18n";
@@ -1,5 +1,5 @@
import { useMemo, useState } from "react";
import { FloppyDisk, Lightbulb, NotePencil, Trash } from "@phosphor-icons/react";
import { FloppyDisk, Lightbulb, NotePencil, Trash } from "../ui/icons";
import type { KnowledgeEntryRecord } from "@shared/types";
import { ActionButton, ConfirmDialog, InlineNotice, Input, ListFrame, ListRow, Modal, Select, StatusPill, TextArea } from "../ui";
import { useT } from "../../i18n";
@@ -1,5 +1,5 @@
import { useMemo, useState } from "react";
import { CalendarBlank, FloppyDisk, NotePencil, Trash } from "@phosphor-icons/react";
import { CalendarBlank, FloppyDisk, NotePencil, Trash } from "../ui/icons";
import type { AgentRecord, MeetingRecord } from "@shared/types";
import { ActionButton, ConfirmDialog, InlineNotice, Input, ListFrame, ListRow, Modal, Select, StatusPill } from "../ui";
import { useT } from "../../i18n";
@@ -1,4 +1,4 @@
import { Plus } from "@phosphor-icons/react";
import { Plus } from "../ui/icons";
import { ActionButton } from "../ui";
export function SectionHeader({
@@ -1,5 +1,5 @@
import { useMemo, useState } from "react";
import { FloppyDisk, NotePencil, Rows, Trash } from "@phosphor-icons/react";
import { FloppyDisk, NotePencil, Rows, Trash } from "../ui/icons";
import type { SprintRecord } from "@shared/types";
import { ActionButton, ConfirmDialog, InlineNotice, Input, ListFrame, ListRow, Modal, Select, StatusPill, TextArea } from "../ui";
import { useT } from "../../i18n";
+1 -1
View File
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { CheckCircle, SignIn } from "@phosphor-icons/react";
import { CheckCircle, SignIn } from "./ui/icons";
import type { ConnectorRecord } from "@shared/types";
import { unwrap } from "../lib/desktop";
import { ActionButton, InlineNotice, Input, Select, StatusPill, TextArea } from "./ui";
@@ -7,7 +7,7 @@ import {
ShieldCheck,
Warning,
XCircle,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { ActivityRecord, AgentRecord } from "@shared/types";
import { timeAgo } from "../../lib/formatters";
@@ -1,5 +1,5 @@
import { useState, useEffect, useMemo, useCallback } from "react";
import { Warning, X } from "@phosphor-icons/react";
import { Warning, X } from "../ui/icons";
import { AnimatePresence, motion } from "framer-motion";
import type { AgentRecord, BudgetIncidentRecord, SectionId } from "@shared/types";
import { useReducedMotion } from "../ui";
@@ -7,7 +7,7 @@ import {
ShieldCheck,
Warning,
XCircle,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type {
ActivityRecord,
AgentRecord,
@@ -1,5 +1,5 @@
import { useMemo } from "react";
import { Briefcase, Robot } from "@phosphor-icons/react";
import { Briefcase, Robot } from "../ui/icons";
import type { AgentRecord, RunRecord, TaskRecord } from "@shared/types";
interface KanbanProps {
@@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
import { Warning, ArrowClockwise, X, Trash } from "@phosphor-icons/react";
import { Warning, ArrowClockwise, X, Trash } from "../ui/icons";
import type { DesktopEvent } from "@shared/types/events";
interface InterruptedRun {
@@ -1,4 +1,4 @@
import { ChartLine } from "@phosphor-icons/react";
import { ChartLine } from "../../ui/icons";
interface ChartCardProps {
title: string;
@@ -1,6 +1,6 @@
import { useMemo, useRef, useState } from "react"
import { useVirtualizer } from "@tanstack/react-virtual"
import { Lightning, MagnifyingGlass } from "@phosphor-icons/react"
import { Lightning, MagnifyingGlass } from "../ui/icons"
import type { ActivityRecord } from "@shared/types"
import { useT } from "../../i18n"
import { formatTime } from "../../lib/formatters"
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react"
import { Warning } from "@phosphor-icons/react"
import { Warning } from "../ui/icons"
import type { BudgetStatusSummary, ProfileSnapshot } from "@shared/types"
import { formatMoney } from "../../lib/formatters"
import { ListFrame, ListRow } from "../ui"
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from "react";
import { ArrowSquareOut, FloppyDisk, Plus, Trash } from "@phosphor-icons/react";
import { ArrowSquareOut, FloppyDisk, Plus, Trash } from "../ui/icons";
import type { ConnectorRecord } from "@shared/types";
import { unwrap } from "../../lib/desktop";
import {
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from "react";
import { CheckCircle, Warning } from "@phosphor-icons/react";
import { CheckCircle, Warning } from "../ui/icons";
import type { BudgetIncidentRecord } from "@shared/types";
import { ActionButton, EmptyState, ListFrame, ListRow } from "../ui";
import { formatTime } from "../../lib/formatters";
@@ -1,4 +1,4 @@
import { CaretDown, CaretRight } from "@phosphor-icons/react";
import { CaretDown, CaretRight } from "../ui/icons";
import type { ProfileSnapshot } from "@shared/types";
import { COMPATIBLE_PROVIDERS } from "../company-onboarding/ProvidersStepShared";
@@ -138,7 +138,7 @@ export function ToggleSwitch({ checked, onChange, label }: { checked: boolean; o
/* Model toggle list */
/* ------------------------------------------------------------------ */
import { X as XIcon } from "@phosphor-icons/react";
import { X as XIcon } from "../ui/icons";
export function ModelToggleList({
models,
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from "react";
import { FloppyDisk, SignIn } from "@phosphor-icons/react";
import { FloppyDisk, SignIn } from "../ui/icons";
import type { ConnectorRecord } from "@shared/types";
import { unwrap } from "../../lib/desktop";
import {
@@ -1,4 +1,4 @@
import { Robot } from "@phosphor-icons/react"
import { Robot } from "../ui/icons"
import type { AgentRecord, TaskRecord } from "@shared/types"
import { useT } from "../../i18n"
import { EmptyState, ListFrame } from "../ui"
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from "react";
import { Plus, ShieldCheck, Trash, Warning } from "@phosphor-icons/react";
import { Plus, ShieldCheck, Trash, Warning } from "../ui/icons";
import type { BudgetPolicyRecord, BudgetStatusSummary } from "@shared/types";
import { ActionButton, EmptyState, ListFrame, ListRow } from "../ui";
import { PolicyFormModal } from "./PolicyFormModal";
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react"
import { ArrowClockwise, CheckCircle, ClockCounterClockwise, Download, Trash } from "@phosphor-icons/react"
import { ArrowClockwise, CheckCircle, ClockCounterClockwise, Download, Trash } from "../ui/icons"
import type { ProfileSnapshot, SecretRecord } from "@shared/types"
import type { AppLocale } from "@shared/locale"
import { APP_LOCALES, LOCALE_LABELS } from "@shared/locale"
@@ -1,4 +1,4 @@
import { Clock, Link as LinkIcon } from "@phosphor-icons/react"
import { Clock, Link as LinkIcon } from "../ui/icons"
import { platformConfig } from "../social/social-config"
import type { SocialPlatform } from "@shared/types"
import { safeJson } from "../../lib/safe-json"
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react"
import { Robot, ArrowRight } from "@phosphor-icons/react"
import { Robot, ArrowRight } from "../ui/icons"
import type { CommentRecord, ProfileSnapshot } from "@shared/types"
import { useT } from "../../i18n"
import { formatTime } from "../../lib/formatters"
@@ -1,6 +1,6 @@
import { useState } from "react"
import { AnimatePresence, motion } from "framer-motion"
import { ListChecks } from "@phosphor-icons/react"
import { ListChecks } from "../ui/icons"
import type { GoalRecord, ProfileSnapshot, ProjectRecord, WorkspaceRecord, TaskRecord } from "@shared/types"
import { useT } from "../../i18n"
import { unwrap } from "../../lib/desktop"
@@ -1,5 +1,5 @@
import { useState, useMemo } from "react"
import { CheckCircle, ListChecks, Pencil, Play, ShieldCheck, Trash, XCircle, Warning, Robot, ArrowRight } from "@phosphor-icons/react"
import { CheckCircle, ListChecks, Pencil, Play, ShieldCheck, Trash, XCircle, Warning, Robot, ArrowRight } from "../ui/icons"
import type { CommentRecord, GoalRecord, ProfileSnapshot, ProjectRecord, RunRecord, TaskRecord, TaskStatus, WorkspaceRecord } from "@shared/types"
import { useT } from "../../i18n"
import { formatMoney, formatTime } from "../../lib/formatters"
@@ -1,5 +1,5 @@
import { useState } from "react"
import { FolderOpen } from "@phosphor-icons/react"
import { FolderOpen } from "../ui/icons"
import type { ProjectRecord } from "@shared/types"
import { useT } from "../../i18n"
import { unwrap } from "../../lib/desktop"
@@ -1,4 +1,4 @@
import { ArrowSquareOut } from "@phosphor-icons/react"
import { ArrowSquareOut } from "../ui/icons"
import type { AgentRecord, DocumentRecord, ProjectRecord, RunRecord, TaskRecord, WorkspaceRecord } from "@shared/types"
import { useT } from "../../i18n"
import { formatTime } from "../../lib/formatters"
@@ -1,5 +1,5 @@
import { useState } from "react"
import { ArrowSquareOut, FolderOpen, Trash } from "@phosphor-icons/react"
import { ArrowSquareOut, FolderOpen, Trash } from "../ui/icons"
import type { ProjectRecord, WorkspaceRecord } from "@shared/types"
import { useT } from "../../i18n"
import { unwrap } from "../../lib/desktop"
@@ -1,5 +1,5 @@
import { useMemo, useState } from "react"
import { CheckCircle } from "@phosphor-icons/react"
import { CheckCircle } from "../../ui/icons"
import type { ApprovalRecord, DocumentRecord } from "@shared/types"
import { extractApprovalDocumentReferences, type ApprovalDocumentReference } from "@shared/approval-documents"
import { unwrap } from "../../../lib/desktop"
@@ -1,4 +1,4 @@
import { Briefcase, Robot } from "@phosphor-icons/react"
import { Briefcase, Robot } from "../../ui/icons"
import type { AgentRecord, ApprovalRecord, TaskRecord } from "@shared/types"
import { formatTime } from "../../../lib/formatters"
import { StatusPill } from "../../ui"
@@ -1,4 +1,4 @@
import { CheckCircle, ClockCounterClockwise, Trash, XCircle } from "@phosphor-icons/react"
import { CheckCircle, ClockCounterClockwise, Trash, XCircle } from "../../ui/icons"
import { ActionButton, TextArea } from "../../ui"
import { useT } from "../../../i18n"
@@ -1,5 +1,5 @@
import { useMemo, useState } from "react"
import { CaretDown, CaretUp } from "@phosphor-icons/react"
import { CaretDown, CaretUp } from "../../ui/icons"
import type { AgentRecord, ApprovalRecord, DocumentRecord } from "@shared/types"
import { useApprovalPayload } from "./useApprovalPayload"
@@ -1,5 +1,5 @@
import { useMemo } from "react"
import { Clock } from "@phosphor-icons/react"
import { Clock } from "../../ui/icons"
import { InlineNotice } from "../../ui"
export type ScheduleMode = "immediate" | "scheduled"
@@ -1,7 +1,7 @@
import type { ApprovalRecord } from "@shared/types"
import {
Robot, CheckSquare, Play, ShieldCheck, Gear, FolderOpen, Key, Target, Briefcase, Buildings,
} from "@phosphor-icons/react"
} from "../ui/icons"
import { safeJson } from "../../lib/safe-json"
export function describeActionError(error: unknown) {
@@ -4,7 +4,7 @@ import {
Check,
UserPlus,
X,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { AgentRecord, ApprovalRecord } from "@shared/types";
import { useT } from "../../i18n";
import { getAgentInitials } from "../../lib/formatters";
+1 -1
View File
@@ -4,7 +4,7 @@ import {
Bell,
Robot,
Tray,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { InboxItem, InboxItemType, SectionId } from "@shared/types";
import { timeAgo } from "../../lib/formatters";
import { useT } from "../../i18n";
@@ -1,4 +1,4 @@
import { Target } from "@phosphor-icons/react";
import { Target } from "../ui/icons";
import type { CompanyMetrics, SectionId } from "@shared/types";
import { formatDuration, formatMoney, getAgentInitials } from "../../lib/formatters";
import { useT } from "../../i18n";
@@ -4,7 +4,7 @@ import {
Clock,
Heartbeat,
Warning,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { SectionId, StandupReport } from "@shared/types";
import { getAgentInitials } from "../../lib/formatters";
import { useT } from "../../i18n";
@@ -6,7 +6,7 @@ import {
Warning,
Eye,
ChatCircle,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { InboxItemType } from "@shared/types";
export const typeConfig: Record<InboxItemType, { icon: React.ElementType; color: string; bg: string; label: string }> = {
@@ -1,6 +1,6 @@
import { useRef } from "react"
import { useVirtualizer } from "@tanstack/react-virtual"
import { CheckCircle } from "@phosphor-icons/react"
import { CheckCircle } from "../ui/icons"
import type { AgentRecord, ConnectorRecord, WorkspaceRecord } from "@shared/types"
import { EmptyState, StatusPill } from "../ui"
import { useT } from "../../i18n"
@@ -1,4 +1,4 @@
import { CheckCircle } from "@phosphor-icons/react";
import { CheckCircle } from "../ui/icons";
import type { AgentRecord, GoalRecord } from "@shared/types";
import { EmptyState, ListFrame, ListRow, StatusPill } from "../ui";
import { useT } from "../../i18n";
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Heartbeat } from "@phosphor-icons/react";
import { Heartbeat } from "../ui/icons";
import type { AgentRecord, ConnectorRecord } from "@shared/types";
import { getAgentInitials } from "../../lib/formatters";
import { EmptyState } from "../ui";
@@ -1,4 +1,4 @@
import { CheckCircle } from "@phosphor-icons/react";
import { CheckCircle } from "../ui/icons";
import type { AgentRecord, GoalRecord, ProjectRecord, WorkspaceRecord } from "@shared/types";
import { EmptyState, ListFrame, ListRow, StatusPill } from "../ui";
import { useT } from "../../i18n";
@@ -1,6 +1,6 @@
import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { Robot } from "@phosphor-icons/react";
import { Robot } from "../../../ui/icons";
import { DEPARTMENT_OPTIONS } from "@shared/constants";
import type {
AgentRecord,
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { Pencil, Trash } from "@phosphor-icons/react";
import { Pencil, Trash } from "../../../ui/icons";
import { DEPARTMENT_OPTIONS } from "@shared/constants";
import type {
AgentRecord,
@@ -1,5 +1,5 @@
import { useState } from "react";
import { Pencil, Target, Trash } from "@phosphor-icons/react";
import { Pencil, Target, Trash } from "../../ui/icons";
import type { AgentRecord, GoalRecord } from "@shared/types";
import { ActionButton, Input, Select, TextArea } from "../../ui";
import { ConfirmDelete } from "../helpers";
@@ -1,4 +1,4 @@
import { Heartbeat, Lightning } from "@phosphor-icons/react";
import { Heartbeat, Lightning } from "../ui/icons";
import type { AgentRecord } from "@shared/types";
import { ActionButton, BudgetBar, InlineConfirmDelete, Select } from "../ui";
import { formatTime } from "../../lib/formatters";
@@ -1,5 +1,5 @@
import { useState } from "react";
import { Kanban, Pencil, Trash } from "@phosphor-icons/react";
import { Kanban, Pencil, Trash } from "../../ui/icons";
import type { AgentRecord, GoalRecord, ProjectRecord } from "@shared/types";
import { ActionButton, Input, Select, TextArea } from "../../ui";
import { ConfirmDelete } from "../helpers";
+1 -1
View File
@@ -4,7 +4,7 @@ import {
Lightning,
ListChecks,
WarningCircle,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { AgentRecord, RunRecord, TaskRecord, WorkspaceRecord } from "@shared/types";
import { formatMoney, formatTime } from "../../lib/formatters";
import { ActionButton, Panel, StatusPill } from "../ui";
@@ -0,0 +1,206 @@
import { useEffect, useMemo, useState } from "react";
import { MagnifyingGlass } from "../../ui/icons";
import type { CredentialSummary } from "@shared/contracts/schemas-credentials";
import { ProviderRow } from "./ProviderRow";
const desktop = (typeof window !== "undefined" ? window.agentCompany : null) as
| (Window["agentCompany"] | null);
/** Provider catalog mirrored from the main process for renderer-only use.
* Keep in sync with src/main/connector-definitions.ts when the catalog grows.
* Each entry is referenced by its connectorId in IPC traffic. */
export interface ProvidersPanelEntry {
id: string;
label: string;
kind: "oauth" | "api_key" | "azure" | "aws" | "gcp_adc";
}
const DEFAULT_CATALOG: ProvidersPanelEntry[] = [
{ id: "claude-pro", label: "Claude Pro / Max", kind: "oauth" },
{ id: "chatgpt-codex", label: "ChatGPT Plus / Pro (Codex)", kind: "oauth" },
{ id: "github-copilot", label: "GitHub Copilot", kind: "oauth" },
{ id: "gemini-cli", label: "Google Gemini CLI", kind: "oauth" },
{ id: "antigravity", label: "Google Antigravity", kind: "oauth" },
{ id: "anthropic", label: "Anthropic API", kind: "api_key" },
{ id: "openai", label: "OpenAI API", kind: "api_key" },
{ id: "google", label: "Google Gemini API", kind: "api_key" },
{ id: "mistral", label: "Mistral", kind: "api_key" },
{ id: "groq", label: "Groq", kind: "api_key" },
{ id: "cerebras", label: "Cerebras", kind: "api_key" },
{ id: "xai", label: "xAI", kind: "api_key" },
{ id: "openrouter", label: "OpenRouter", kind: "api_key" },
{ id: "vercel-ai-gateway", label: "Vercel AI Gateway", kind: "api_key" },
{ id: "zai", label: "ZAI", kind: "api_key" },
{ id: "opencode", label: "OpenCode Zen", kind: "api_key" },
{ id: "opencode-go", label: "OpenCode Go", kind: "api_key" },
{ id: "huggingface", label: "Hugging Face", kind: "api_key" },
{ id: "kimi-coding", label: "Kimi For Coding", kind: "api_key" },
{ id: "minimax", label: "MiniMax", kind: "api_key" },
{ id: "minimax-cn", label: "MiniMax (China)", kind: "api_key" },
{ id: "fireworks", label: "Fireworks AI", kind: "api_key" },
{ id: "fireworks-firepass", label: "Fireworks Fire Pass", kind: "api_key" },
{ id: "azure-openai", label: "Azure OpenAI", kind: "azure" },
{ id: "amazon-bedrock", label: "AWS Bedrock", kind: "aws" },
{ id: "google-vertex", label: "Google Vertex AI", kind: "gcp_adc" },
];
const FILTERS: Array<{ id: "all" | "configured" | "available"; label: string }> = [
{ id: "all", label: "All" },
{ id: "configured", label: "Connected" },
{ id: "available", label: "Available" },
];
const GROUP_ORDER: Array<{ id: ProvidersPanelEntry["kind"]; label: string }> = [
{ id: "oauth", label: "Sign in" },
{ id: "api_key", label: "API key" },
{ id: "azure", label: "Azure" },
{ id: "aws", label: "AWS" },
{ id: "gcp_adc", label: "Google Cloud" },
];
interface Props {
catalog?: ProvidersPanelEntry[];
}
export function ProvidersPanel({ catalog }: Props) {
const entries = catalog ?? DEFAULT_CATALOG;
const [credentials, setCredentials] = useState<Map<string, CredentialSummary>>(new Map());
const [filter, setFilter] = useState<"all" | "configured" | "available">("all");
const [search, setSearch] = useState("");
useEffect(() => {
if (!desktop) return;
let cancelled = false;
void desktop.listCredentials().then((result) => {
if (cancelled || !result.ok) return;
setCredentials(new Map(result.data.map((row) => [row.connectorId, row])));
});
const unsubscribe = desktop.subscribe((event) => {
if (event.type !== "credentials-changed") return;
void desktop.listCredentials().then((result) => {
if (!result.ok) return;
setCredentials(new Map(result.data.map((row) => [row.connectorId, row])));
});
});
return () => {
cancelled = true;
unsubscribe();
};
}, []);
const filtered = useMemo(() => {
return entries.filter((entry) => {
const hasCredential = credentials.has(entry.id);
if (filter === "configured" && !hasCredential) return false;
if (filter === "available" && hasCredential) return false;
if (search.trim()) {
const needle = search.trim().toLowerCase();
return entry.label.toLowerCase().includes(needle) || entry.id.includes(needle);
}
return true;
});
}, [entries, credentials, filter, search]);
const grouped = useMemo(() => {
const byKind = new Map<ProvidersPanelEntry["kind"], ProvidersPanelEntry[]>();
for (const entry of filtered) {
const list = byKind.get(entry.kind) ?? [];
list.push(entry);
byKind.set(entry.kind, list);
}
return GROUP_ORDER.map((group) => ({
...group,
items: byKind.get(group.id) ?? [],
})).filter((group) => group.items.length > 0);
}, [filtered]);
const configuredCount = useMemo(
() => entries.filter((entry) => credentials.has(entry.id)).length,
[entries, credentials],
);
return (
<section aria-label="Providers" className="space-y-4">
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="relative w-full sm:max-w-xs">
<MagnifyingGlass
size={14}
weight="regular"
className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground/70"
aria-hidden
/>
<input
type="search"
placeholder="Search providers"
value={search}
onChange={(event) => setSearch(event.target.value)}
aria-label="Search providers"
className="h-9 w-full rounded-md border border-border bg-background pl-8 pr-3 text-[13px] text-foreground outline-none transition-colors placeholder:text-muted-foreground/60 focus:border-foreground/40"
/>
</div>
<div className="flex items-center gap-3">
<div className="hidden text-[11px] font-medium text-muted-foreground sm:block">
{configuredCount} / {entries.length} connected
</div>
<div
role="tablist"
aria-label="Filter providers"
className="inline-flex rounded-md border border-border bg-background p-0.5"
>
{FILTERS.map((item) => {
const active = filter === item.id;
return (
<button
key={item.id}
type="button"
role="tab"
aria-selected={active}
onClick={() => setFilter(item.id)}
className={
"rounded px-3 py-1 text-[11px] font-medium transition-colors " +
(active
? "bg-foreground text-background"
: "text-muted-foreground hover:text-foreground")
}
>
{item.label}
</button>
);
})}
</div>
</div>
</div>
{grouped.length === 0 ? (
<div className="rounded-md border border-dashed border-border py-10 text-center text-[12px] text-muted-foreground">
No providers match the current filter.
</div>
) : (
<div className="space-y-6">
{grouped.map((group) => (
<div key={group.id}>
<div className="mb-2 flex items-baseline justify-between">
<h3 className="text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
{group.label}
</h3>
<span className="text-[10px] text-muted-foreground/70">
{group.items.length}
</span>
</div>
<ul className="divide-y divide-border overflow-hidden rounded-md border border-border bg-background/40">
{group.items.map((entry) => (
<ProviderRow
key={entry.id}
entry={entry}
credential={credentials.get(entry.id) ?? null}
/>
))}
</ul>
</div>
))}
</div>
)}
</section>
);
}
@@ -7,7 +7,7 @@ import {
Link,
PuzzlePiece,
Trash,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { AgentRecord, SkillRecord, SkillUpdateStatus } from "@shared/types";
import { useAppStore } from "../../state/store";
import { ActionButton, StatusPill } from "../ui";
@@ -5,7 +5,7 @@ import {
FileText,
FolderOpen,
FolderSimple,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { FileInventoryEntry } from "@shared/types";
export type SkillTreeNode = {
@@ -4,7 +4,7 @@ import {
GithubLogo,
Globe,
Link,
} from "@phosphor-icons/react";
} from "../ui/icons";
import { Modal, ActionButton, Input } from "../ui";
import { useAppStore } from "../../state/store";
+1 -1
View File
@@ -7,7 +7,7 @@ import {
Globe,
Link,
PuzzlePiece,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { SkillRecord } from "@shared/types";
import { SkillFileTree, buildTree } from "./SkillFileTree";
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useState } from "react";
import {
MagnifyingGlass,
Plus,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { AgentRecord } from "@shared/types";
import { useAppStore } from "../../state/store";
import { ActionButton, EmptyState } from "../ui";
@@ -1,4 +1,4 @@
import { ShieldCheck, SignIn, Trash } from "@phosphor-icons/react";
import { ShieldCheck, SignIn, Trash } from "../ui/icons";
import type { SocialAccountRecord } from "@shared/types";
import { timeAgo } from "../../lib/formatters";
import { platformConfig } from "./social-config";
@@ -2,7 +2,7 @@ import {
ArrowSquareOut,
ClockCounterClockwise,
Robot,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { BrowserActionRecord } from "@shared/types";
import { timeAgo } from "../../lib/formatters";
import { actionTypeLabels } from "./social-config";
@@ -1,5 +1,5 @@
import { useState } from "react";
import { SignIn } from "@phosphor-icons/react";
import { SignIn } from "../ui/icons";
import type { SocialPlatform } from "@shared/types";
import { ActionButton, Modal } from "../ui";
import { platformConfig } from "./social-config";
@@ -1,6 +1,6 @@
import { useCallback, useState } from "react";
import { AnimatePresence } from "framer-motion";
import { Browser, Megaphone, Plus } from "@phosphor-icons/react";
import { Browser, Megaphone, Plus } from "../ui/icons";
import type { BrowserActionRecord, SocialAccountRecord, SocialPlatform } from "@shared/types";
import { ActionButton } from "../ui";
import { useT } from "../../i18n";
@@ -25,7 +25,7 @@ import {
Notebook,
MusicNote,
Lightbulb,
} from "@phosphor-icons/react";
} from "../ui/icons";
import type { SocialPlatform } from "@shared/types";
export const platformConfig: Record<SocialPlatform, { label: string; color: string; bgColor: string; icon: ElementType }> = {
+124
View File
@@ -0,0 +1,124 @@
/**
* Central barrel for all Phosphor icons used across the renderer.
*
* Every renderer component imports icons from this module so that:
* - bundle tree-shaking has a single module boundary to look at,
* - typos like `BriefCase` vs `Briefcase` surface in one place,
* - swapping icon sets later means touching one file.
*
* Keep this list sorted alphabetically. When a new icon is needed,
* add it here first, then import from "@/components/ui/icons" (or the
* relative path from the file). Raw `@phosphor-icons/react` imports
* outside this file should be treated as a regression.
*/
export {
ArrowBendUpLeft,
ArrowClockwise,
ArrowCounterClockwise,
ArrowRight,
ArrowSquareOut,
ArrowsClockwise,
At,
Bell,
BookOpen,
Brain,
Briefcase,
Browser,
Buildings,
CalendarBlank,
Camera,
CaretDown,
CaretRight,
CaretUp,
CaretUpDown,
ChartLine,
ChatCircle,
ChatCircleDots,
ChatTeardrop,
Check,
CheckCircle,
CheckSquare,
Circle,
CircleNotch,
Clock,
ClockCounterClockwise,
Command,
Copy,
Cpu,
CurrencyCircleDollar,
DiscordLogo,
Download,
EnvelopeSimple,
Eye,
FacebookLogo,
FileCode,
FileText,
Fire,
FloppyDisk,
FolderOpen,
FolderSimple,
Funnel,
Gear,
GithubLogo,
Globe,
GlobeHemisphereWest,
GlobeSimple,
HardDrive,
Hash,
Heart,
Heartbeat,
Hourglass,
InstagramLogo,
Kanban,
Key,
Lightbulb,
Lightning,
Link,
LinkedinLogo,
ListChecks,
MagnifyingGlass,
Megaphone,
Minus,
MonitorPlay,
MusicNote,
NotePencil,
Notebook,
PaperPlaneTilt,
Paperclip,
Pause,
Pencil,
PinterestLogo,
Play,
Plugs,
Plus,
PuzzlePiece,
RedditLogo,
Robot,
Rocket,
Rows,
ShieldCheck,
SidebarSimple,
SignIn,
SlidersHorizontal,
Square,
SquaresFour,
Target,
TelegramLogo,
Terminal,
TerminalWindow,
TiktokLogo,
Timer,
Trash,
Tray,
UserCircle,
UserPlus,
UsersThree,
Warning,
WarningCircle,
WhatsappLogo,
XCircle,
XLogo,
YoutubeLogo,
} from "@phosphor-icons/react";
export { X } from "@phosphor-icons/react";
export type { Icon } from "@phosphor-icons/react";
+1 -1
View File
@@ -18,7 +18,7 @@ import {
ShieldCheck,
Megaphone,
FolderOpen,
} from "@phosphor-icons/react";
} from "../components/ui/icons";
import type { AppLocale } from "@shared/locale";
type NavItemDef = { id: SectionId; labelKey: string; icon: typeof SquaresFour };
+1 -1
View File
@@ -6,7 +6,7 @@ import {
Target,
TerminalWindow,
UsersThree,
} from "@phosphor-icons/react";
} from "../components/ui/icons";
import type { AgentRecord, GoalRecord, ProjectRecord, RunRecord, SectionId, TaskRecord } from "@shared/types";
import { ListFrame, ListRow, StatusPill } from "../components/ui";
+1 -1
View File
@@ -1,6 +1,6 @@
import { useMemo } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { FolderOpen, TerminalWindow, X } from "@phosphor-icons/react";
import { FolderOpen, TerminalWindow, X } from "../components/ui/icons";
import type { RunRecord } from "@shared/types";
import { ActionButton, Select, StatusPill } from "../components/ui";
import { formatMoney, formatTime } from "../lib/formatters";
+1 -1
View File
@@ -1,5 +1,5 @@
import { AnimatePresence, motion } from "framer-motion";
import { WarningCircle } from "@phosphor-icons/react";
import { WarningCircle } from "../components/ui/icons";
import type { SectionId } from "@shared/types";
import { ErrorBoundary } from "../components/ui";
import { OrganizationSections } from "./sections/OrganizationSections";
+1 -1
View File
@@ -6,7 +6,7 @@ import {
Plus,
SidebarSimple,
Trash,
} from "@phosphor-icons/react";
} from "../components/ui/icons";
import type { CompanyRecord, ProfileSnapshot, SectionId } from "@shared/types";
import { SectionButton } from "../components/ui";
import { NEW_ENTITY_ID } from "../lib/constants";
@@ -5,7 +5,7 @@ import {
Kanban,
ListChecks,
Target,
} from "@phosphor-icons/react";
} from "../../components/ui/icons";
import { ConnectorEditor } from "../../components/connectors";
import { KanbanBoard } from "../../components/dashboard";
import { TwoPaneLayout } from "../../components/TwoPaneLayout";
@@ -4,7 +4,7 @@ import {
Target,
UserPlus,
Kanban,
} from "@phosphor-icons/react";
} from "../../components/ui/icons";
import {
AgentCreator,
AgentEditor,