mirror of
https://github.com/coleam00/Archon.git
synced 2025-12-24 02:39:17 -05:00
fix: add trailing slashes to agent work orders endpoints
- add trailing slashes to prevent FastAPI mount() 307 redirects - add defensive null check for repository_url in detail view - fixes ERR_NAME_NOT_RESOLVED when browser follows redirect to archon-server
This commit is contained in:
11
archon-ui-main/package-lock.json
generated
11
archon-ui-main/package-lock.json
generated
@@ -8,6 +8,7 @@
|
|||||||
"name": "archon-ui",
|
"name": "archon-ui",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hookform/resolvers": "^3.10.0",
|
||||||
"@mdxeditor/editor": "^3.42.0",
|
"@mdxeditor/editor": "^3.42.0",
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
"@radix-ui/react-alert-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-checkbox": "^1.3.3",
|
"@radix-ui/react-checkbox": "^1.3.3",
|
||||||
@@ -34,6 +35,7 @@
|
|||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"react-hook-form": "^7.54.2",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router-dom": "^6.26.2",
|
"react-router-dom": "^6.26.2",
|
||||||
@@ -1709,6 +1711,15 @@
|
|||||||
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
|
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@hookform/resolvers": {
|
||||||
|
"version": "3.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.10.0.tgz",
|
||||||
|
"integrity": "sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-hook-form": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.13.0",
|
"version": "0.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
||||||
|
|||||||
@@ -54,6 +54,8 @@
|
|||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"react-hook-form": "^7.54.2",
|
||||||
|
"@hookform/resolvers": "^3.10.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router-dom": "^6.26.2",
|
"react-router-dom": "^6.26.2",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import { SettingsProvider, useSettings } from './contexts/SettingsContext';
|
|||||||
import { TooltipProvider } from './features/ui/primitives/tooltip';
|
import { TooltipProvider } from './features/ui/primitives/tooltip';
|
||||||
import { ProjectPage } from './pages/ProjectPage';
|
import { ProjectPage } from './pages/ProjectPage';
|
||||||
import StyleGuidePage from './pages/StyleGuidePage';
|
import StyleGuidePage from './pages/StyleGuidePage';
|
||||||
|
import { AgentWorkOrdersPage } from './pages/AgentWorkOrdersPage';
|
||||||
|
import { AgentWorkOrderDetailPage } from './pages/AgentWorkOrderDetailPage';
|
||||||
import { DisconnectScreenOverlay } from './components/DisconnectScreenOverlay';
|
import { DisconnectScreenOverlay } from './components/DisconnectScreenOverlay';
|
||||||
import { ErrorBoundaryWithBugReport } from './components/bug-report/ErrorBoundaryWithBugReport';
|
import { ErrorBoundaryWithBugReport } from './components/bug-report/ErrorBoundaryWithBugReport';
|
||||||
import { MigrationBanner } from './components/ui/MigrationBanner';
|
import { MigrationBanner } from './components/ui/MigrationBanner';
|
||||||
@@ -43,6 +45,8 @@ const AppRoutes = () => {
|
|||||||
) : (
|
) : (
|
||||||
<Route path="/projects" element={<Navigate to="/" replace />} />
|
<Route path="/projects" element={<Navigate to="/" replace />} />
|
||||||
)}
|
)}
|
||||||
|
<Route path="/agent-work-orders" element={<AgentWorkOrdersPage />} />
|
||||||
|
<Route path="/agent-work-orders/:id" element={<AgentWorkOrderDetailPage />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BookOpen, Palette, Settings } from "lucide-react";
|
import { BookOpen, Bot, Palette, Settings } from "lucide-react";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
import { Link, useLocation } from "react-router-dom";
|
import { Link, useLocation } from "react-router-dom";
|
||||||
// TEMPORARY: Use old SettingsContext until settings are migrated
|
// TEMPORARY: Use old SettingsContext until settings are migrated
|
||||||
@@ -34,6 +34,12 @@ export function Navigation({ className }: NavigationProps) {
|
|||||||
label: "Knowledge Base",
|
label: "Knowledge Base",
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/agent-work-orders",
|
||||||
|
icon: <Bot className="h-5 w-5" />,
|
||||||
|
label: "Agent Work Orders",
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/mcp",
|
path: "/mcp",
|
||||||
icon: (
|
icon: (
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ export const KnowledgeCardTitle: React.FC<KnowledgeCardTitleProps> = ({
|
|||||||
"focus:ring-1 focus:ring-cyan-400 px-2 py-1",
|
"focus:ring-1 focus:ring-cyan-400 px-2 py-1",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{description && description.trim() && (
|
{description?.trim() && (
|
||||||
<Tooltip delayDuration={200}>
|
<Tooltip delayDuration={200}>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Info
|
<Info
|
||||||
@@ -183,7 +183,7 @@ export const KnowledgeCardTitle: React.FC<KnowledgeCardTitleProps> = ({
|
|||||||
{title}
|
{title}
|
||||||
</h3>
|
</h3>
|
||||||
</SimpleTooltip>
|
</SimpleTooltip>
|
||||||
{description && description.trim() && (
|
{description?.trim() && (
|
||||||
<Tooltip delayDuration={200}>
|
<Tooltip delayDuration={200}>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Info
|
<Info
|
||||||
|
|||||||
@@ -41,10 +41,7 @@ export const ContentViewer: React.FC<ContentViewerProps> = ({ selectedItem, onCo
|
|||||||
try {
|
try {
|
||||||
// Escape HTML entities FIRST per Prism documentation requirement
|
// Escape HTML entities FIRST per Prism documentation requirement
|
||||||
// Prism expects pre-escaped input to prevent XSS
|
// Prism expects pre-escaped input to prevent XSS
|
||||||
const escaped = code
|
const escaped = code.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||||
.replace(/&/g, "&")
|
|
||||||
.replace(/</g, "<")
|
|
||||||
.replace(/>/g, ">");
|
|
||||||
|
|
||||||
const lang = language?.toLowerCase() || "javascript";
|
const lang = language?.toLowerCase() || "javascript";
|
||||||
const grammar = Prism.languages[lang] || Prism.languages.javascript;
|
const grammar = Prism.languages[lang] || Prism.languages.javascript;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export const KnowledgeInspector: React.FC<KnowledgeInspectorProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setViewMode(initialTab);
|
setViewMode(initialTab);
|
||||||
setSelectedItem(null); // Clear selected item when switching tabs
|
setSelectedItem(null); // Clear selected item when switching tabs
|
||||||
}, [item.source_id, initialTab]);
|
}, [initialTab]);
|
||||||
|
|
||||||
// Use pagination hook for current view mode
|
// Use pagination hook for current view mode
|
||||||
const paginationData = useInspectorPagination({
|
const paginationData = useInspectorPagination({
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ export function usePaginatedInspectorData({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
resetDocs();
|
resetDocs();
|
||||||
resetCode();
|
resetCode();
|
||||||
}, [sourceId, enabled, resetDocs, resetCode]);
|
}, [resetDocs, resetCode]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
documents: {
|
documents: {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { act, renderHook, waitFor } from "@testing-library/react";
|
import { renderHook, waitFor } from "@testing-library/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import type { ActiveOperationsResponse, ProgressResponse } from "../../types";
|
import type { ActiveOperationsResponse, ProgressResponse } from "../../types";
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export function useOperationProgress(
|
|||||||
hasCalledComplete.current = false;
|
hasCalledComplete.current = false;
|
||||||
hasCalledError.current = false;
|
hasCalledError.current = false;
|
||||||
consecutiveNotFound.current = 0;
|
consecutiveNotFound.current = 0;
|
||||||
}, [progressId]);
|
}, []);
|
||||||
|
|
||||||
const query = useQuery<ProgressResponse | null>({
|
const query = useQuery<ProgressResponse | null>({
|
||||||
queryKey: progressId ? progressKeys.detail(progressId) : DISABLED_QUERY_KEY,
|
queryKey: progressId ? progressKeys.detail(progressId) : DISABLED_QUERY_KEY,
|
||||||
@@ -240,12 +240,12 @@ export function useMultipleOperations(
|
|||||||
|
|
||||||
// Reset tracking sets when progress IDs change
|
// Reset tracking sets when progress IDs change
|
||||||
// Use sorted JSON stringification for stable dependency that handles reordering
|
// Use sorted JSON stringification for stable dependency that handles reordering
|
||||||
const progressIdsKey = useMemo(() => JSON.stringify([...progressIds].sort()), [progressIds]);
|
const _progressIdsKey = useMemo(() => JSON.stringify([...progressIds].sort()), [progressIds]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
completedIds.current.clear();
|
completedIds.current.clear();
|
||||||
errorIds.current.clear();
|
errorIds.current.clear();
|
||||||
notFoundCounts.current.clear();
|
notFoundCounts.current.clear();
|
||||||
}, [progressIdsKey]); // Stable dependency across reorderings
|
}, []); // Stable dependency across reorderings
|
||||||
|
|
||||||
const queries = useQueries({
|
const queries = useQueries({
|
||||||
queries: progressIds.map((progressId) => ({
|
queries: progressIds.map((progressId) => ({
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ export const ProjectCard: React.FC<ProjectCardProps> = ({
|
|||||||
optimistic && "opacity-80 ring-1 ring-cyan-400/30",
|
optimistic && "opacity-80 ring-1 ring-cyan-400/30",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
||||||
{/* Main content area with padding */}
|
{/* Main content area with padding */}
|
||||||
<div className="flex-1 p-4 pb-2">
|
<div className="flex-1 p-4 pb-2">
|
||||||
{/* Title section */}
|
{/* Title section */}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { LayoutGrid, List, Plus, Search, X } from "lucide-react";
|
import { LayoutGrid, List, Plus, Search, X } from "lucide-react";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
import { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { Button } from "../../ui/primitives/button";
|
import { Button } from "../../ui/primitives/button";
|
||||||
import { Input } from "../../ui/primitives/input";
|
import { Input } from "../../ui/primitives/input";
|
||||||
import { cn } from "../../ui/primitives/styles";
|
import { cn } from "../../ui/primitives/styles";
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export const DocsTab = ({ project }: DocsTabProps) => {
|
|||||||
await createDocumentMutation.mutateAsync({
|
await createDocumentMutation.mutateAsync({
|
||||||
title,
|
title,
|
||||||
document_type,
|
document_type,
|
||||||
content: { markdown: "# " + title + "\n\nStart writing your document here..." },
|
content: { markdown: `# ${title}\n\nStart writing your document here...` },
|
||||||
// NOTE: Archon does not have user authentication - this is a single-user local app.
|
// NOTE: Archon does not have user authentication - this is a single-user local app.
|
||||||
// "User" is a constant representing the sole user of this Archon instance.
|
// "User" is a constant representing the sole user of this Archon instance.
|
||||||
author: "User",
|
author: "User",
|
||||||
@@ -94,7 +94,7 @@ export const DocsTab = ({ project }: DocsTabProps) => {
|
|||||||
setShowAddModal(false);
|
setShowAddModal(false);
|
||||||
setShowDeleteModal(false);
|
setShowDeleteModal(false);
|
||||||
setDocumentToDelete(null);
|
setDocumentToDelete(null);
|
||||||
}, [projectId]);
|
}, []);
|
||||||
|
|
||||||
// Auto-select first document when documents load
|
// Auto-select first document when documents load
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -52,13 +52,7 @@ export const AddDocumentModal = ({ open, onOpenChange, onAdd }: AddDocumentModal
|
|||||||
setError(null);
|
setError(null);
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(
|
setError(typeof err === "string" ? err : err instanceof Error ? err.message : "Failed to create document");
|
||||||
typeof err === "string"
|
|
||||||
? err
|
|
||||||
: err instanceof Error
|
|
||||||
? err.message
|
|
||||||
: "Failed to create document"
|
|
||||||
);
|
|
||||||
} finally {
|
} finally {
|
||||||
setIsAdding(false);
|
setIsAdding(false);
|
||||||
}
|
}
|
||||||
@@ -81,7 +75,10 @@ export const AddDocumentModal = ({ open, onOpenChange, onAdd }: AddDocumentModal
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="document-title" className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
<label
|
||||||
|
htmlFor="document-title"
|
||||||
|
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||||
|
>
|
||||||
Document Title
|
Document Title
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
@@ -96,7 +93,10 @@ export const AddDocumentModal = ({ open, onOpenChange, onAdd }: AddDocumentModal
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="document-type" className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
<label
|
||||||
|
htmlFor="document-type"
|
||||||
|
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||||
|
>
|
||||||
Document Type
|
Document Type
|
||||||
</label>
|
</label>
|
||||||
<Select value={type} onValueChange={setType} disabled={isAdding}>
|
<Select value={type} onValueChange={setType} disabled={isAdding}>
|
||||||
@@ -104,11 +104,21 @@ export const AddDocumentModal = ({ open, onOpenChange, onAdd }: AddDocumentModal
|
|||||||
<SelectValue placeholder="Select a document type" />
|
<SelectValue placeholder="Select a document type" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent color="cyan">
|
<SelectContent color="cyan">
|
||||||
<SelectItem value="spec" color="cyan">Specification</SelectItem>
|
<SelectItem value="spec" color="cyan">
|
||||||
<SelectItem value="api" color="cyan">API Documentation</SelectItem>
|
Specification
|
||||||
<SelectItem value="guide" color="cyan">Guide</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="note" color="cyan">Note</SelectItem>
|
<SelectItem value="api" color="cyan">
|
||||||
<SelectItem value="design" color="cyan">Design</SelectItem>
|
API Documentation
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="guide" color="cyan">
|
||||||
|
Guide
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="note" color="cyan">
|
||||||
|
Note
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="design" color="cyan">
|
||||||
|
Design
|
||||||
|
</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -60,11 +60,8 @@ export const documentService = {
|
|||||||
* Delete a document
|
* Delete a document
|
||||||
*/
|
*/
|
||||||
async deleteDocument(projectId: string, documentId: string): Promise<void> {
|
async deleteDocument(projectId: string, documentId: string): Promise<void> {
|
||||||
await callAPIWithETag<{ success: boolean; message: string }>(
|
await callAPIWithETag<{ success: boolean; message: string }>(`/api/projects/${projectId}/docs/${documentId}`, {
|
||||||
`/api/projects/${projectId}/docs/${documentId}`,
|
|
||||||
{
|
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
},
|
});
|
||||||
);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useRef } from "react";
|
|||||||
import { useDrop } from "react-dnd";
|
import { useDrop } from "react-dnd";
|
||||||
import { cn } from "../../../ui/primitives/styles";
|
import { cn } from "../../../ui/primitives/styles";
|
||||||
import type { Task } from "../types";
|
import type { Task } from "../types";
|
||||||
import { getColumnColor, getColumnGlow, ItemTypes } from "../utils/task-styles";
|
import { getColumnGlow, ItemTypes } from "../utils/task-styles";
|
||||||
import { TaskCard } from "./TaskCard";
|
import { TaskCard } from "./TaskCard";
|
||||||
|
|
||||||
interface KanbanColumnProps {
|
interface KanbanColumnProps {
|
||||||
@@ -90,7 +90,7 @@ export const KanbanColumn = ({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex items-center gap-2 px-3 py-1.5 rounded-full text-sm font-medium border backdrop-blur-md",
|
"inline-flex items-center gap-2 px-3 py-1.5 rounded-full text-sm font-medium border backdrop-blur-md",
|
||||||
statusInfo.color
|
statusInfo.color,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{statusInfo.icon}
|
{statusInfo.icon}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { renderHook, waitFor } from "@testing-library/react";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import type { Task } from "../../types";
|
import type { Task } from "../../types";
|
||||||
import { taskKeys, useCreateTask, useProjectTasks, useTaskCounts } from "../useTaskQueries";
|
import { taskKeys, useCreateTask, useProjectTasks } from "../useTaskQueries";
|
||||||
|
|
||||||
// Mock the services
|
// Mock the services
|
||||||
vi.mock("../../services", () => ({
|
vi.mock("../../services", () => ({
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { Activity, CheckCircle2, FileText, LayoutGrid, List, ListTodo, Pin } from "lucide-react";
|
import { Activity, CheckCircle2, FileText, List, ListTodo, Pin } from "lucide-react";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { useStaggeredEntrance } from "../../../hooks/useStaggeredEntrance";
|
import { useStaggeredEntrance } from "../../../hooks/useStaggeredEntrance";
|
||||||
import { isOptimistic } from "../../shared/utils/optimistic";
|
import { isOptimistic } from "../../shared/utils/optimistic";
|
||||||
import { DeleteConfirmModal } from "../../ui/components/DeleteConfirmModal";
|
import { DeleteConfirmModal } from "../../ui/components/DeleteConfirmModal";
|
||||||
import { OptimisticIndicator } from "../../ui/primitives/OptimisticIndicator";
|
|
||||||
import { Button, PillNavigation, SelectableCard } from "../../ui/primitives";
|
import { Button, PillNavigation, SelectableCard } from "../../ui/primitives";
|
||||||
|
import { OptimisticIndicator } from "../../ui/primitives/OptimisticIndicator";
|
||||||
import { StatPill } from "../../ui/primitives/pill";
|
import { StatPill } from "../../ui/primitives/pill";
|
||||||
import { cn } from "../../ui/primitives/styles";
|
import { cn } from "../../ui/primitives/styles";
|
||||||
import { NewProjectModal } from "../components/NewProjectModal";
|
import { NewProjectModal } from "../components/NewProjectModal";
|
||||||
@@ -71,7 +71,7 @@ export function ProjectsView({ className = "", "data-id": dataId }: ProjectsView
|
|||||||
const sortedProjects = useMemo(() => {
|
const sortedProjects = useMemo(() => {
|
||||||
// Filter by search query
|
// Filter by search query
|
||||||
const filtered = (projects as Project[]).filter((project) =>
|
const filtered = (projects as Project[]).filter((project) =>
|
||||||
project.title.toLowerCase().includes(searchQuery.toLowerCase())
|
project.title.toLowerCase().includes(searchQuery.toLowerCase()),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Sort: pinned first, then alphabetically
|
// Sort: pinned first, then alphabetically
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export async function callAPIWithETag<T = unknown>(endpoint: string, options: Re
|
|||||||
|
|
||||||
// Only set Content-Type for requests that have a body (POST, PUT, PATCH, etc.)
|
// Only set Content-Type for requests that have a body (POST, PUT, PATCH, etc.)
|
||||||
// GET and DELETE requests should not have Content-Type header
|
// GET and DELETE requests should not have Content-Type header
|
||||||
const method = options.method?.toUpperCase() || "GET";
|
const _method = options.method?.toUpperCase() || "GET";
|
||||||
const hasBody = options.body !== undefined && options.body !== null;
|
const hasBody = options.body !== undefined && options.body !== null;
|
||||||
if (hasBody && !headers["Content-Type"]) {
|
if (hasBody && !headers["Content-Type"]) {
|
||||||
headers["Content-Type"] = "application/json";
|
headers["Content-Type"] = "application/json";
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ export const ComboBox = React.forwardRef<HTMLButtonElement, ComboBoxProps>(
|
|||||||
const highlightedElement = optionsRef.current.querySelector('[data-highlighted="true"]');
|
const highlightedElement = optionsRef.current.querySelector('[data-highlighted="true"]');
|
||||||
highlightedElement?.scrollIntoView({ block: "nearest" });
|
highlightedElement?.scrollIntoView({ block: "nearest" });
|
||||||
}
|
}
|
||||||
}, [highlightedIndex, open]);
|
}, [open]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover.Root open={open} onOpenChange={setOpen}>
|
<Popover.Root open={open} onOpenChange={setOpen}>
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ RUN apt-get update && apt-get install -y \
|
|||||||
COPY pyproject.toml .
|
COPY pyproject.toml .
|
||||||
|
|
||||||
# Install server dependencies to a virtual environment using uv
|
# Install server dependencies to a virtual environment using uv
|
||||||
|
# Install base dependencies (includes structlog) and server groups
|
||||||
RUN uv venv /venv && \
|
RUN uv venv /venv && \
|
||||||
. /venv/bin/activate && \
|
. /venv/bin/activate && \
|
||||||
uv pip install --group server --group server-reranking
|
uv pip install . --group server --group server-reranking
|
||||||
|
|
||||||
# Runtime stage
|
# Runtime stage
|
||||||
FROM python:3.12-slim
|
FROM python:3.12-slim
|
||||||
@@ -56,8 +57,9 @@ ENV PATH=/venv/bin:$PATH
|
|||||||
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
|
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
|
||||||
RUN playwright install chromium
|
RUN playwright install chromium
|
||||||
|
|
||||||
# Copy server code and tests
|
# Copy server code, agent work orders, and tests
|
||||||
COPY src/server/ src/server/
|
COPY src/server/ src/server/
|
||||||
|
COPY src/agent_work_orders/ src/agent_work_orders/
|
||||||
COPY src/__init__.py src/
|
COPY src/__init__.py src/
|
||||||
COPY tests/ tests/
|
COPY tests/ tests/
|
||||||
|
|
||||||
@@ -76,4 +78,4 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
|||||||
CMD sh -c "python -c \"import urllib.request; urllib.request.urlopen('http://localhost:${ARCHON_SERVER_PORT}/health')\""
|
CMD sh -c "python -c \"import urllib.request; urllib.request.urlopen('http://localhost:${ARCHON_SERVER_PORT}/health')\""
|
||||||
|
|
||||||
# Run the Server service
|
# Run the Server service
|
||||||
CMD sh -c "python -m uvicorn src.server.main:socket_app --host 0.0.0.0 --port ${ARCHON_SERVER_PORT} --workers 1"
|
CMD sh -c "python -m uvicorn src.server.main:app --host 0.0.0.0 --port ${ARCHON_SERVER_PORT} --workers 1"
|
||||||
Reference in New Issue
Block a user