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
15 changes: 15 additions & 0 deletions app/(oss)/orchestration/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use client";

import { OrchestrationLayout } from "@/app/components/OrchestrationLayout";
import { OrchestrationHome } from "@/app/components/OrchestrationHome";

export default function OrchestrationsPage() {
return (
<OrchestrationLayout
title="Orchestrations"
description="Manage operational workflows and automation"
>
<OrchestrationHome />
</OrchestrationLayout>
);
}
17 changes: 17 additions & 0 deletions app/(oss)/orchestration/plans/[planId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use client';

import React from 'react';
import { useParams } from 'next/navigation';
import { OrchestrationLayout } from '@/app/components/OrchestrationLayout';
import { PlanDetail } from '@/app/components/PlanDetail';

export default function PlanDetailPage() {
const params = useParams();
const planId = params.planId as string;

return (
<OrchestrationLayout title="Plan Details">
<PlanDetail planId={planId} />
</OrchestrationLayout>
);
}
16 changes: 16 additions & 0 deletions app/(oss)/orchestration/plans/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use client';

import React from 'react';
import { OrchestrationLayout } from '@/app/components/OrchestrationLayout';
import { PlanBrowser } from '@/app/components/PlanBrowser';

export default function PlansPage() {
return (
<OrchestrationLayout
title="Workflow Plans"
description="Browse and manage orchestration workflow plans"
>
<PlanBrowser />
</OrchestrationLayout>
);
}
17 changes: 17 additions & 0 deletions app/(oss)/orchestration/runs/[runId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use client';

import React from 'react';
import { useParams } from 'next/navigation';
import { OrchestrationLayout } from '@/app/components/OrchestrationLayout';
import { RunDetail } from '@/app/components/RunDetail';

export default function RunDetailPage() {
const params = useParams();
const runId = params.runId as string;

return (
<OrchestrationLayout title="Run Details">
<RunDetail runId={runId} />
</OrchestrationLayout>
);
}
65 changes: 65 additions & 0 deletions app/(oss)/orchestration/runs/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use client';

import React, { Suspense } from 'react';
import { useSearchParams } from 'next/navigation';
import { OrchestrationLayout } from '@/app/components/OrchestrationLayout';
import { RunBrowser } from '@/app/components/RunBrowser';
import { RunQuery, RunStatus } from '@/app/lib/types';
import { parseScope } from '@/app/lib/scope';

function RunsPageContent() {
const searchParams = useSearchParams();

// Parse initial query from URL parameters
const initialQuery: Partial<RunQuery> = {};

const statusParam = searchParams.get('status') || searchParams.get('statuses');
if (statusParam) {
const statuses = statusParam.split(',') as RunStatus[];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Type assertion assumes URL params contain valid RunStatus values without validation. Should this validate that the status values are actually valid RunStatus enum values before casting?

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/(oss)/orchestration/runs/page.tsx
Line: 18:18

Comment:
**logic:** Type assertion assumes URL params contain valid RunStatus values without validation. Should this validate that the status values are actually valid RunStatus enum values before casting?

How can I resolve this? If you propose a fix, please make it concise.

initialQuery.statuses = statuses;
}

const planIdParam = searchParams.get('planId') || searchParams.get('planIds');
if (planIdParam) {
initialQuery.planIds = planIdParam.split(',').filter(Boolean);
}

const limitParam = searchParams.get('limit');
if (limitParam) {
const limit = Number(limitParam);
if (!Number.isNaN(limit) && limit > 0) {
initialQuery.limit = limit;
}
}

const scopeParam = searchParams.get('scope');
const parsedScope = parseScope(scopeParam);
const service = searchParams.get('service');
const environment = searchParams.get('environment');
const team = searchParams.get('team');

if (parsedScope) {
initialQuery.scope = parsedScope;
} else if (service || environment || team) {
initialQuery.scope = {
service: service || undefined,
environment: environment || undefined,
team: team || undefined,
};
}

return <RunBrowser initialQuery={initialQuery} />;
}

export default function RunsPage() {
return (
<OrchestrationLayout
title="Workflow Runs"
description="Browse and monitor orchestration workflow runs"
>
<Suspense fallback={<div className="p-8 text-center text-gray-500">Loading...</div>}>
<RunsPageContent />
</Suspense>
</OrchestrationLayout>
);
}
7 changes: 3 additions & 4 deletions app/components/(enterprise)/copilot/CollapsibleCodeBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useState } from "react";
import { useState } from "react";
import { CodeBlock } from "@/app/lib/ui";
import { trace } from "next/dist/trace";

export function CollapsibleCodeBlock({
code,
Expand All @@ -16,13 +15,13 @@ export function CollapsibleCodeBlock({
const [isExpanded, setIsExpanded] = useState(defaultOpen);

return (
<div className="space-y-3">
<div className="space-y-3">
<button
onClick={() => setIsExpanded(!isExpanded)}
className="flex w-full items-center justify-between text-left"
>
<p className="text-[11px] font-semibold uppercase tracking-wide text-slate-500">
{title}
{title}
</p>
<div className="flex items-center gap-2">
<svg
Expand Down
4 changes: 0 additions & 4 deletions app/components/(enterprise)/copilot/ToolExecutionsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@ export function ToolExecutionsView({ trace }: ToolExecutionsViewProps) {
(sum, it) => sum + it.plannedTools.length,
0
);
const totalHeuristics = trace.iterations.reduce(
(sum, it) => sum + it.heuristicModifications.length,
0
);
const totalAddedTools = trace.iterations.reduce((sum, it) => {
const added = it.heuristicModifications.flatMap((mod) =>
mod.action === "inject" ? mod.affectedTools || [] : []
Expand Down
1 change: 1 addition & 0 deletions app/components/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const allNavItems: NavItem[] = [
{ href: "/alerts", label: "Alerts" },
{ href: "/logs", label: "Logs" },
{ href: "/metrics", label: "Metrics" },
{ href: "/orchestration", label: "Orchestration" },
{ href: "/deployments", label: "Deployments" },
{ href: "/tickets", label: "Tickets" },
{ href: "/services", label: "Services" },
Expand Down
47 changes: 47 additions & 0 deletions app/components/MarkdownText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use client';

import React from 'react';

type MarkdownTextProps = {
text?: string;
className?: string;
};

function renderPlainText(segment: string, keyPrefix: string) {
const lines = segment.split('\n');
return lines.map((line, index) => (
<React.Fragment key={`${keyPrefix}-line-${index}`}>
{line}
{index < lines.length - 1 && <br />}
</React.Fragment>
));
}

export function MarkdownText({ text, className }: MarkdownTextProps) {
if (!text) return null;

const parts = text.split('`');

return (
<span className={className}>
{parts.map((part, index) => {
if (index % 2 === 1) {
return (
<code
key={`code-${index}`}
className="rounded bg-gray-100 px-1 py-0.5 font-mono text-[12px] text-gray-700"
>
{part}
</code>
);
Comment on lines +28 to +36
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Empty code blocks will be rendered when consecutive backticks appear in the input (e.g., 'test``code' creates an empty code element). Consider filtering out empty segments.

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/components/MarkdownText.tsx
Line: 28:36

Comment:
**logic:** Empty code blocks will be rendered when consecutive backticks appear in the input (e.g., 'test``code' creates an empty code element). Consider filtering out empty segments.

How can I resolve this? If you propose a fix, please make it concise.

}

return (
<React.Fragment key={`text-${index}`}>
{renderPlainText(part, `text-${index}`)}
</React.Fragment>
);
})}
</span>
);
}
28 changes: 28 additions & 0 deletions app/components/OrchestrationHome.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use client";

import { RunStatusSummary } from "@/app/components/RunStatusSummary";
import { RecentPlans } from "@/app/components/RecentPlans";
import { QuickActions } from "@/app/components/QuickActions";

export function OrchestrationHome() {
return (
<div className="grid grid-cols-1 gap-6">
{/* Welcome Section */}
<div className="rounded-xl border border-slate-200 bg-gradient-to-br from-slate-50 to-white p-6">
<h2 className="text-lg font-semibold text-slate-900 mb-3">Workflow Orchestration</h2>
<p className="text-sm text-slate-600 mb-4">
Automate your operations with runbooks, playbooks, and checklists. Streamline complex workflows and ensure consistency across your team.
</p>
</div>

{/* Quick Actions */}
<QuickActions />

{/* Status Summary and Recent Plans */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<RunStatusSummary />
<RecentPlans />
</div>
</div>
);
}
25 changes: 25 additions & 0 deletions app/components/OrchestrationLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use client";

import { ReactNode } from "react";
import { AppShell } from "@/app/components/AppShell";

interface OrchestrationLayoutProps {
title: string;
description?: string;
children: ReactNode;
}

export function OrchestrationLayout({
title,
description,
children,
}: OrchestrationLayoutProps) {
return (
<AppShell
title={title}
description={description}
>
{children}
</AppShell>
);
}
100 changes: 100 additions & 0 deletions app/components/PlanBrowser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"use client";

import { useCallback, useEffect, useState } from "react";
import { useAsyncState } from "@/app/lib/hooks";
import { queryPlans } from "@/app/lib/orchestration";
import { OrchestrationPlan, PlanQuery } from "@/app/lib/types";
import { PlanGrid } from "@/app/components/PlanGrid";
import { PlanFilters } from "@/app/components/PlanFilters";

export function PlanBrowser() {
const [plans, setPlans] = useState<OrchestrationPlan[]>([]);
const [currentFilters, setCurrentFilters] = useState<Partial<PlanQuery>>({});
const asyncState = useAsyncState();
const { start, succeed, fail } = asyncState;

const loadPlans = useCallback(
async (filters: Partial<PlanQuery> = {}) => {
start();
try {
const result = await queryPlans({
...filters,
limit: 50, // Load up to 50 plans
});
setPlans(result || []);
succeed();
} catch (err) {
fail(err);
}
},
[start, succeed, fail],
);

const handleFilterChange = (filters: Partial<PlanQuery>) => {
setCurrentFilters(filters);
loadPlans(filters);
};

// Load initial plans
useEffect(() => {
const timeoutId = setTimeout(() => {
void loadPlans();
}, 0);
return () => clearTimeout(timeoutId);
}, [loadPlans]);

return (
<div className="space-y-6">
{/* Filters */}
<PlanFilters
onFilterChange={handleFilterChange}
loading={asyncState.loading}
/>

{/* Results Header */}
<div className="flex items-center justify-between">
<div>
<h2 className="text-xl font-semibold text-slate-900">
Available Plans
</h2>
<p className="text-sm text-slate-600 mt-1">
{asyncState.loading ? (
"Loading plans..."
) : (
`${plans.length} plan${plans.length !== 1 ? 's' : ''} found`
)}
</p>
</div>

{/* Sort Options */}
<div className="flex items-center gap-2">
<label className="text-sm font-medium text-slate-700">Sort by:</label>
<select className="rounded-lg border border-slate-300 px-3 py-1 text-sm focus:border-[#55cfd0] focus:outline-none focus:ring-1 focus:ring-[#55cfd0]">
<option value="title">Title</option>
<option value="type">Type</option>
<option value="steps">Step Count</option>
</select>
Comment on lines +72 to +76
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Sort dropdown is not functional - no onChange handler or state management. Should this sorting functionality be implemented now or is it intended for a future iteration?

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/components/PlanBrowser.tsx
Line: 66:70

Comment:
**logic:** Sort dropdown is not functional - no onChange handler or state management. Should this sorting functionality be implemented now or is it intended for a future iteration?

How can I resolve this? If you propose a fix, please make it concise.

</div>
</div>

{/* Plan Grid */}
<PlanGrid
plans={plans}
loading={asyncState.loading}
error={asyncState.error}
/>

{/* Load More Button (if needed) */}
{plans.length >= 50 && !asyncState.loading && (
<div className="text-center pt-6">
<button
onClick={() => loadPlans({ ...currentFilters, limit: plans.length + 50 })}
Comment on lines +88 to +91
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Load more logic may not work as intended - it passes limit as total count rather than maintaining offset

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/components/PlanBrowser.tsx
Line: 82:85

Comment:
**logic:** Load more logic may not work as intended - it passes limit as total count rather than maintaining offset

How can I resolve this? If you propose a fix, please make it concise.

className="inline-flex items-center px-6 py-3 border border-slate-300 text-sm font-medium rounded-lg text-slate-700 bg-white hover:bg-slate-50 transition"
>
Load More Plans
</button>
</div>
)}
</div>
);
}
Loading