fix(web): remove old "运行总览" task UI; Overview shows new template agents
The old /deployments (运行总览) + /tasks/$id pages rendered the new template agents with meaningless old sub-task fields (待确认/sub_agile/子任务流/智能体任务图/产物/ SK快照/合并时间线 — all empty). Removed the whole old-model UI cluster and pointed the Overview dashboard at the real new endpoint: - deleted features/agent-console, features/agent-hub, features/tasks and the routes /deployments and /tasks/$id. - cockpit (Overview) now lists deployed template agents from /api/heicode/agents (status counts + recent agents), not the old listAgentDeployments. - removed the "运行总览" sidebar item + dead /deployments links in footer / top-nav / sidebar-config. - routeTree regenerated; frontend build + tsc clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Vendored
+1
-1
@@ -20,7 +20,7 @@
|
|||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
|
|
||||||
<meta name="theme-color" content="#7B6BE3" />
|
<meta name="theme-color" content="#7B6BE3" />
|
||||||
<link rel="icon" href="/favicon.ico"><script defer src="/static/js/vendor-radix.829c7e3fad.js"></script><script defer src="/static/js/vendor-tanstack.632dbe8908.js"></script><script defer src="/static/js/lib-react.5c8909c28c.js"></script><script defer src="/static/js/6374.bc21d8b214.js"></script><script defer src="/static/js/index.13c9f5d1a3.js"></script><link href="/static/css/index.592272f49e.css" rel="stylesheet"></head>
|
<link rel="icon" href="/favicon.ico"><script defer src="/static/js/vendor-radix.829c7e3fad.js"></script><script defer src="/static/js/vendor-tanstack.632dbe8908.js"></script><script defer src="/static/js/lib-react.5c8909c28c.js"></script><script defer src="/static/js/6374.bc21d8b214.js"></script><script defer src="/static/js/index.046d6d6bc8.js"></script><link href="/static/css/index.48ece32abf.css" rel="stylesheet"></head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ export function Footer(props: FooterProps) {
|
|||||||
{
|
{
|
||||||
title: t('footer.columns.docs.title'),
|
title: t('footer.columns.docs.title'),
|
||||||
links: [
|
links: [
|
||||||
{ text: t('Deployments'), href: '/deployments' },
|
|
||||||
{ text: t('API Keys'), href: '/keys' },
|
{ text: t('API Keys'), href: '/keys' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,521 +0,0 @@
|
|||||||
import { api } from '@/lib/api'
|
|
||||||
|
|
||||||
export type AgentSubMode = 'agile' | 'waterfall'
|
|
||||||
|
|
||||||
/** Sub-agent cloud/runtime binding (passed to Agent on deploy). */
|
|
||||||
export type AgentRuntimeExecution = {
|
|
||||||
profile_id?: string
|
|
||||||
cloud_principal_refs?: string[]
|
|
||||||
network_policy_ref?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/** SK allow/deny policy attached to the agent in the deployment plan. */
|
|
||||||
export type AgentSKAccessPolicy = {
|
|
||||||
policy_ref?: string
|
|
||||||
deny_skill_ids?: string[]
|
|
||||||
inherit_deployment_defaults?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Git-backed SK source (`type: git`). */
|
|
||||||
export type AgentRepoRef = {
|
|
||||||
connection_id?: string
|
|
||||||
repo_url?: string
|
|
||||||
ref: string
|
|
||||||
paths: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Single SK source entry (git or upload). */
|
|
||||||
export type AgentSKSource = {
|
|
||||||
type?: string
|
|
||||||
artifact_id?: string
|
|
||||||
mime?: string
|
|
||||||
repo_ref?: AgentRepoRef
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentAgentPlan = {
|
|
||||||
role_template: string
|
|
||||||
goal: string
|
|
||||||
default_model_id?: string
|
|
||||||
sk_sources?: AgentSKSource[]
|
|
||||||
runtime_execution?: AgentRuntimeExecution
|
|
||||||
sk_access_policy?: AgentSKAccessPolicy
|
|
||||||
resource_grants?: Array<{
|
|
||||||
grant_id?: string
|
|
||||||
resource_id?: string
|
|
||||||
resource_type?: string
|
|
||||||
user_id?: string
|
|
||||||
binding_scope?: string
|
|
||||||
target_role?: string
|
|
||||||
target_agent_ref?: string
|
|
||||||
permission_scope?: string[]
|
|
||||||
constraints?: Record<string, string>
|
|
||||||
metadata?: Record<string, string>
|
|
||||||
status?: 'pending' | 'active' | 'disabled' | 'revoked'
|
|
||||||
secret_ref?: string
|
|
||||||
audit?: Record<string, string>
|
|
||||||
}>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentBudget = {
|
|
||||||
max_tokens: number
|
|
||||||
max_cost_usd: number
|
|
||||||
max_duration_sec: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentUserContext = {
|
|
||||||
user_id: string
|
|
||||||
email?: string
|
|
||||||
role?: string
|
|
||||||
channel_id?: string
|
|
||||||
subscription_tier?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentBillingContext = {
|
|
||||||
provider?: 'newapi'
|
|
||||||
newapi_user_ref?: string
|
|
||||||
newapi_group?: string
|
|
||||||
quota_ref?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentAgentRuntime = {
|
|
||||||
platform?: 'agent'
|
|
||||||
agents?: Array<{
|
|
||||||
role: string
|
|
||||||
model_ref: string
|
|
||||||
instance_count: number
|
|
||||||
}>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentConstraints = {
|
|
||||||
/** Runtime model allow-list for Agent deployments; not a NewAPI billing map. */
|
|
||||||
allowed_model_ids?: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentOrchestrationMetadata = {
|
|
||||||
/**
|
|
||||||
* Compatibility field for Agent routing scope; UI treats this as user scope,
|
|
||||||
* not billing tenant.
|
|
||||||
*/
|
|
||||||
tenant_id: string
|
|
||||||
/**
|
|
||||||
* Compatibility field for Agent routing scope; UI treats this as resource
|
|
||||||
* scope, not project control.
|
|
||||||
*/
|
|
||||||
project_id: string
|
|
||||||
correlation_id: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentOrchestrationPlan = {
|
|
||||||
intent_id: string
|
|
||||||
template_hint: string
|
|
||||||
objective: string
|
|
||||||
sub_mode?: AgentSubMode
|
|
||||||
risk_level: 'low' | 'medium' | 'high'
|
|
||||||
budget: AgentBudget
|
|
||||||
user_context: AgentUserContext
|
|
||||||
billing_context?: AgentBillingContext
|
|
||||||
agent_runtime?: AgentAgentRuntime
|
|
||||||
agents: AgentAgentPlan[]
|
|
||||||
constraints: AgentConstraints
|
|
||||||
metadata: AgentOrchestrationMetadata
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentCreateDeploymentBody = {
|
|
||||||
orchestration_plan: AgentOrchestrationPlan
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentCreateDeploymentResult = {
|
|
||||||
deployment_id: string
|
|
||||||
sub_mode?: AgentSubMode
|
|
||||||
status: string
|
|
||||||
agent_instances?: Array<{
|
|
||||||
instance_id?: string
|
|
||||||
role?: string
|
|
||||||
phase?: string
|
|
||||||
}>
|
|
||||||
permission_manifest?: AgentPermissionManifest
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentPermissionManifest = {
|
|
||||||
user_id?: string
|
|
||||||
binding_scope?: string
|
|
||||||
agent_role?: string
|
|
||||||
target_agent_ref?: string
|
|
||||||
resource_grants?: Array<{
|
|
||||||
grant_id?: string
|
|
||||||
resource_id?: string
|
|
||||||
resource_type?: string
|
|
||||||
resource_ref?: string
|
|
||||||
allowed_actions?: string[]
|
|
||||||
constraints?: Record<string, string>
|
|
||||||
secret_ref?: string
|
|
||||||
status?: string
|
|
||||||
}>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentDeployment = {
|
|
||||||
deployment_id: string
|
|
||||||
// Client-facing mode (sub_agile | swarm) + Manager-judged display_status,
|
|
||||||
// both populated by the backend list/detail responses.
|
|
||||||
mode?: string
|
|
||||||
display_status?: string
|
|
||||||
sub_mode?: AgentSubMode
|
|
||||||
status: string
|
|
||||||
phase: string
|
|
||||||
runtime_state?: string
|
|
||||||
runtime_deployment_id?: string
|
|
||||||
runtime_swarm_id?: string
|
|
||||||
runtime_last_sync_at?: string
|
|
||||||
failure_reason?: string
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
permission_manifest?: AgentPermissionManifest
|
|
||||||
orchestration_plan: {
|
|
||||||
intent_id?: string
|
|
||||||
template_hint?: string
|
|
||||||
objective?: string
|
|
||||||
sub_mode?: AgentSubMode
|
|
||||||
risk_level?: string
|
|
||||||
budget?: AgentBudget
|
|
||||||
agents?: AgentAgentPlan[]
|
|
||||||
constraints?: AgentConstraints
|
|
||||||
metadata?: AgentOrchestrationMetadata
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentRuntimeDiagnostics = {
|
|
||||||
deployment_id: string
|
|
||||||
runtime_mode?: 'agent' | 'swarm' | string
|
|
||||||
sub_mode?: AgentSubMode
|
|
||||||
runtime_deployment_id?: string
|
|
||||||
runtime_swarm_id?: string
|
|
||||||
data_source?: string
|
|
||||||
http_status?: number
|
|
||||||
status?: string
|
|
||||||
phase?: string
|
|
||||||
progress?: unknown
|
|
||||||
error_message?: string
|
|
||||||
agents?: Array<Record<string, unknown>>
|
|
||||||
artifacts?: Array<Record<string, unknown>>
|
|
||||||
metrics?: Record<string, unknown>
|
|
||||||
warnings?: string[]
|
|
||||||
checked_at?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentApprovalRequest = {
|
|
||||||
approval_id: string
|
|
||||||
user_id: number
|
|
||||||
deployment_id?: string
|
|
||||||
binding_scope?: string
|
|
||||||
operation: string
|
|
||||||
resource_id: string
|
|
||||||
resource_type: string
|
|
||||||
resource_scope?: string
|
|
||||||
target_role: string
|
|
||||||
risk_level: 'low' | 'medium' | 'high' | 'critical'
|
|
||||||
requires_credential: boolean
|
|
||||||
credential_lease_id?: string
|
|
||||||
status: 'pending' | 'approved' | 'rejected' | 'expired'
|
|
||||||
requested_by?: string
|
|
||||||
decided_by?: string
|
|
||||||
request_reason?: string
|
|
||||||
decision_reason?: string
|
|
||||||
ttl_seconds: number
|
|
||||||
expires_at: number
|
|
||||||
decided_at?: number
|
|
||||||
created_at?: number
|
|
||||||
updated_at?: number
|
|
||||||
credential_lease?: AgentCredentialLease
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentCredentialLease = {
|
|
||||||
lease_id: string
|
|
||||||
credential_ref: string
|
|
||||||
approval_id: string
|
|
||||||
user_id: number
|
|
||||||
deployment_id?: string
|
|
||||||
binding_scope?: string
|
|
||||||
resource_id: string
|
|
||||||
resource_type: string
|
|
||||||
resource_scope?: string
|
|
||||||
target_role: string
|
|
||||||
status: 'active' | 'expired' | 'revoked'
|
|
||||||
ttl_seconds: number
|
|
||||||
expires_at: number
|
|
||||||
revoked_at?: number
|
|
||||||
created_at?: number
|
|
||||||
updated_at?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
type ApiEnvelope<T> = { success: boolean; data?: T; message?: string }
|
|
||||||
|
|
||||||
export type GitSourceUsage = 'project' | 'sk' | 'combined'
|
|
||||||
|
|
||||||
export type GitSource = {
|
|
||||||
id: number
|
|
||||||
user_id: number
|
|
||||||
tenant_id?: string
|
|
||||||
name: string
|
|
||||||
provider: string
|
|
||||||
repo_url: string
|
|
||||||
ref: string
|
|
||||||
paths: string[]
|
|
||||||
usage: GitSourceUsage | string
|
|
||||||
status: string
|
|
||||||
created_at?: number
|
|
||||||
updated_at?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GitSourcePayload = {
|
|
||||||
tenant_id?: string
|
|
||||||
name: string
|
|
||||||
provider: string
|
|
||||||
repo_url: string
|
|
||||||
ref: string
|
|
||||||
paths: string[]
|
|
||||||
usage: GitSourceUsage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Platform-recommended role catalog shape. Mirrors backend
|
|
||||||
// `AgentRoleTemplate` in controller/agent_role_template.go. The
|
|
||||||
// six canonical roles come from docs/product-package §13.3.3 —
|
|
||||||
// keys are stable identifiers, display strings can be translated.
|
|
||||||
export type AgentRoleTemplate = {
|
|
||||||
key: string
|
|
||||||
display_name: string
|
|
||||||
summary: string
|
|
||||||
default_model: string
|
|
||||||
default_permissions: string[]
|
|
||||||
risk_level: 'low' | 'medium' | 'high'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cached at module level — the canonical six-role catalog doesn't
|
|
||||||
// change between page loads, so we avoid an extra request every
|
|
||||||
// time the create-deployment sheet opens.
|
|
||||||
let _roleTemplateCache: AgentRoleTemplate[] | null = null
|
|
||||||
|
|
||||||
export async function listAgentRoleTemplates(): Promise<AgentRoleTemplate[]> {
|
|
||||||
if (_roleTemplateCache) return _roleTemplateCache
|
|
||||||
const res = await api.get<ApiEnvelope<{ items?: AgentRoleTemplate[] }>>(
|
|
||||||
'/api/agent/role-templates'
|
|
||||||
)
|
|
||||||
const items = res.data?.data?.items ?? []
|
|
||||||
if (items.length > 0) {
|
|
||||||
_roleTemplateCache = items
|
|
||||||
}
|
|
||||||
return items
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function listAgentDeployments(): Promise<AgentDeployment[]> {
|
|
||||||
const res = await api.get<ApiEnvelope<{ items?: AgentDeployment[] }>>(
|
|
||||||
'/api/agent/user/deployments'
|
|
||||||
)
|
|
||||||
return res.data?.data?.items ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function listAgentDeploymentsQuiet(): Promise<AgentDeployment[]> {
|
|
||||||
const res = await api.get<ApiEnvelope<{ items?: AgentDeployment[] }>>(
|
|
||||||
'/api/agent/user/deployments',
|
|
||||||
{
|
|
||||||
skipBusinessError: true,
|
|
||||||
skipErrorHandler: true,
|
|
||||||
} as Record<string, unknown>
|
|
||||||
)
|
|
||||||
if (!res.data?.success) return []
|
|
||||||
return res.data?.data?.items ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createAgentDeployment(
|
|
||||||
body: AgentCreateDeploymentBody
|
|
||||||
): Promise<AgentCreateDeploymentResult> {
|
|
||||||
const res = await api.post<ApiEnvelope<AgentCreateDeploymentResult>>(
|
|
||||||
'/api/agent/user/deployments',
|
|
||||||
body
|
|
||||||
)
|
|
||||||
const env = res.data
|
|
||||||
if (!env?.success) {
|
|
||||||
throw new Error(env?.message || 'Deployment request failed')
|
|
||||||
}
|
|
||||||
const data = env.data
|
|
||||||
if (!data?.deployment_id) {
|
|
||||||
throw new Error(env?.message || 'Invalid deployment response')
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAgentDeploymentEvents(deploymentId: string) {
|
|
||||||
const res = await api.get<
|
|
||||||
ApiEnvelope<{ items?: Array<Record<string, unknown>> }>
|
|
||||||
>(`/api/agent/user/deployments/${deploymentId}/events`)
|
|
||||||
return res.data?.data?.items ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAgentDeploymentArtifacts(deploymentId: string) {
|
|
||||||
const res = await api.get<
|
|
||||||
ApiEnvelope<{ items?: Array<Record<string, unknown>> }>
|
|
||||||
>(`/api/agent/user/deployments/${deploymentId}/artifacts`)
|
|
||||||
return res.data?.data?.items ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAgentDeploymentSKSnapshots(deploymentId: string) {
|
|
||||||
const res = await api.get<
|
|
||||||
ApiEnvelope<{ items?: Array<Record<string, unknown>> }>
|
|
||||||
>(`/api/agent/user/deployments/${deploymentId}/sk-snapshots`)
|
|
||||||
return res.data?.data?.items ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAgentDeploymentTimeline(deploymentId: string) {
|
|
||||||
const res = await api.get<
|
|
||||||
ApiEnvelope<{
|
|
||||||
callbacks?: Array<Record<string, unknown>>
|
|
||||||
artifacts?: Array<Record<string, unknown>>
|
|
||||||
sk_snapshots?: Array<Record<string, unknown>>
|
|
||||||
timeline?: Array<Record<string, unknown>>
|
|
||||||
}>
|
|
||||||
>(`/api/agent/user/deployments/${deploymentId}/timeline`)
|
|
||||||
return (
|
|
||||||
res.data?.data ?? {
|
|
||||||
callbacks: [],
|
|
||||||
artifacts: [],
|
|
||||||
sk_snapshots: [],
|
|
||||||
timeline: [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAgentRuntimeDiagnostics(
|
|
||||||
deploymentId: string
|
|
||||||
): Promise<AgentRuntimeDiagnostics | null> {
|
|
||||||
const res = await api.get<ApiEnvelope<AgentRuntimeDiagnostics>>(
|
|
||||||
`/api/agent/user/deployments/${deploymentId}/runtime-diagnostics`,
|
|
||||||
{
|
|
||||||
skipBusinessError: true,
|
|
||||||
skipErrorHandler: true,
|
|
||||||
} as Record<string, unknown>
|
|
||||||
)
|
|
||||||
if (!res.data?.success) return null
|
|
||||||
return res.data?.data ?? null
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function simulateAgentDeploymentEvents(
|
|
||||||
deploymentId: string,
|
|
||||||
events?: string[]
|
|
||||||
): Promise<{ deployment_id: string; simulated: boolean; total: number }> {
|
|
||||||
const res = await api.post<
|
|
||||||
ApiEnvelope<{ deployment_id: string; simulated: boolean; total: number }>
|
|
||||||
>(`/api/agent/user/deployments/${deploymentId}/simulate-events`, {
|
|
||||||
events: events ?? [],
|
|
||||||
})
|
|
||||||
const env = res.data
|
|
||||||
if (!env?.success || !env.data) {
|
|
||||||
throw new Error(env?.message || 'simulateAgentDeploymentEvents failed')
|
|
||||||
}
|
|
||||||
return env.data
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAgentAuditLogs() {
|
|
||||||
const res = await api.get<
|
|
||||||
ApiEnvelope<{ items?: Array<Record<string, unknown>> }>
|
|
||||||
>('/api/agent/audit-logs')
|
|
||||||
return res.data?.data?.items ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function listAgentApprovals(params?: {
|
|
||||||
status?: string
|
|
||||||
deployment_id?: string
|
|
||||||
}): Promise<AgentApprovalRequest[]> {
|
|
||||||
const res = await api.get<ApiEnvelope<{ items?: AgentApprovalRequest[] }>>(
|
|
||||||
'/api/agent/approvals',
|
|
||||||
{ params }
|
|
||||||
)
|
|
||||||
return res.data?.data?.items ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function approveAgentApproval(
|
|
||||||
approvalId: string,
|
|
||||||
reason?: string
|
|
||||||
): Promise<AgentApprovalRequest> {
|
|
||||||
const res = await api.post<ApiEnvelope<AgentApprovalRequest>>(
|
|
||||||
`/api/agent/approvals/${approvalId}/approve`,
|
|
||||||
{ reason }
|
|
||||||
)
|
|
||||||
if (!res.data?.success || !res.data.data) {
|
|
||||||
throw new Error(res.data?.message || 'Approve request failed')
|
|
||||||
}
|
|
||||||
return res.data.data
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function rejectAgentApproval(
|
|
||||||
approvalId: string,
|
|
||||||
reason?: string
|
|
||||||
): Promise<AgentApprovalRequest> {
|
|
||||||
const res = await api.post<ApiEnvelope<AgentApprovalRequest>>(
|
|
||||||
`/api/agent/approvals/${approvalId}/reject`,
|
|
||||||
{ reason }
|
|
||||||
)
|
|
||||||
if (!res.data?.success || !res.data.data) {
|
|
||||||
throw new Error(res.data?.message || 'Reject request failed')
|
|
||||||
}
|
|
||||||
return res.data.data
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function listAgentCredentialLeases(params?: {
|
|
||||||
status?: string
|
|
||||||
deployment_id?: string
|
|
||||||
}): Promise<AgentCredentialLease[]> {
|
|
||||||
const res = await api.get<ApiEnvelope<{ items?: AgentCredentialLease[] }>>(
|
|
||||||
'/api/agent/credential-leases',
|
|
||||||
{ params }
|
|
||||||
)
|
|
||||||
return res.data?.data?.items ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function revokeAgentCredentialLease(
|
|
||||||
leaseId: string,
|
|
||||||
reason?: string
|
|
||||||
): Promise<AgentCredentialLease> {
|
|
||||||
const res = await api.post<ApiEnvelope<AgentCredentialLease>>(
|
|
||||||
`/api/agent/credential-leases/${leaseId}/revoke`,
|
|
||||||
{ reason }
|
|
||||||
)
|
|
||||||
if (!res.data?.success || !res.data.data) {
|
|
||||||
throw new Error(res.data?.message || 'Revoke lease failed')
|
|
||||||
}
|
|
||||||
return res.data.data
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAgentSnapshots(deploymentId: string) {
|
|
||||||
const res = await api.get<
|
|
||||||
ApiEnvelope<{ items?: Array<Record<string, unknown>> }>
|
|
||||||
>(`/api/agent/deployments/${deploymentId}/sk-snapshots`, {
|
|
||||||
skipBusinessError: true,
|
|
||||||
skipErrorHandler: true,
|
|
||||||
} as Record<string, unknown>)
|
|
||||||
if (!res.data?.success) return []
|
|
||||||
return res.data?.data?.items ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function listGitSources(): Promise<GitSource[]> {
|
|
||||||
const res =
|
|
||||||
await api.get<ApiEnvelope<{ items?: GitSource[] }>>('/api/git-sources/')
|
|
||||||
return res.data?.data?.items ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createGitSource(
|
|
||||||
body: GitSourcePayload
|
|
||||||
): Promise<GitSource> {
|
|
||||||
const res = await api.post<ApiEnvelope<GitSource>>('/api/git-sources/', body)
|
|
||||||
if (!res.data?.success || !res.data.data) {
|
|
||||||
throw new Error(res.data?.message || 'Create Git source failed')
|
|
||||||
}
|
|
||||||
return res.data.data
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deleteGitSource(id: number): Promise<void> {
|
|
||||||
const res = await api.delete<ApiEnvelope<{ deleted?: boolean }>>(
|
|
||||||
`/api/git-sources/${id}`
|
|
||||||
)
|
|
||||||
if (!res.data?.success) {
|
|
||||||
throw new Error(res.data?.message || 'Delete Git source failed')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,34 +0,0 @@
|
|||||||
import { Link } from '@tanstack/react-router'
|
|
||||||
|
|
||||||
type AgentHubProps = {
|
|
||||||
title: string
|
|
||||||
description: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const quickLinks = [{ title: 'Deployments', to: '/deployments' as const }]
|
|
||||||
|
|
||||||
export function AgentHub(props: AgentHubProps) {
|
|
||||||
return (
|
|
||||||
<div className='mx-auto w-full max-w-5xl p-6'>
|
|
||||||
<div className='mb-5'>
|
|
||||||
<h1 className='text-2xl font-semibold'>{props.title}</h1>
|
|
||||||
<p className='text-muted-foreground mt-2 text-sm'>{props.description}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='grid gap-4 md:grid-cols-3'>
|
|
||||||
{quickLinks.map((item) => (
|
|
||||||
<Link
|
|
||||||
key={item.title}
|
|
||||||
to={item.to}
|
|
||||||
className='bg-card hover:bg-accent/40 rounded-lg border p-4 transition-colors'
|
|
||||||
>
|
|
||||||
<div className='font-medium'>{item.title}</div>
|
|
||||||
<div className='text-muted-foreground mt-1 text-xs'>
|
|
||||||
Open {item.title.toLowerCase()} workspace
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -15,13 +15,26 @@ import {
|
|||||||
import { api } from '@/lib/api'
|
import { api } from '@/lib/api'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import {
|
|
||||||
listAgentDeployments,
|
|
||||||
type AgentDeployment,
|
|
||||||
} from '@/features/agent-console/api'
|
|
||||||
import { WalletStatsCard } from '@/features/wallet/components/wallet-stats-card'
|
import { WalletStatsCard } from '@/features/wallet/components/wallet-stats-card'
|
||||||
import type { UserWalletData } from '@/features/wallet/types'
|
import type { UserWalletData } from '@/features/wallet/types'
|
||||||
|
|
||||||
|
// Deployed template agents (new model).
|
||||||
|
type AgentItem = {
|
||||||
|
agent_id: string
|
||||||
|
template_id: string
|
||||||
|
subdomain: string
|
||||||
|
status: string
|
||||||
|
created_at: string
|
||||||
|
updated_at: string
|
||||||
|
}
|
||||||
|
|
||||||
|
async function listMyAgents(): Promise<AgentItem[]> {
|
||||||
|
const res = await api.get<{ data?: { items?: AgentItem[] } }>(
|
||||||
|
'/api/heicode/agents'
|
||||||
|
)
|
||||||
|
return res.data?.data?.items ?? []
|
||||||
|
}
|
||||||
|
|
||||||
// Current user's OWN balance/usage (NOT the admin-global aggregate) — same
|
// Current user's OWN balance/usage (NOT the admin-global aggregate) — same
|
||||||
// source the 模型与余额 page uses.
|
// source the 模型与余额 page uses.
|
||||||
async function getSelfUsage(): Promise<UserWalletData> {
|
async function getSelfUsage(): Promise<UserWalletData> {
|
||||||
@@ -149,9 +162,10 @@ export function CockpitView() {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const deploymentsQuery = useQuery({
|
const deploymentsQuery = useQuery({
|
||||||
queryKey: ['cockpit', 'deployments'],
|
queryKey: ['cockpit', 'agents'],
|
||||||
queryFn: listAgentDeployments,
|
queryFn: listMyAgents,
|
||||||
refetchInterval: 30_000,
|
refetchInterval: 30_000,
|
||||||
|
retry: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const selfQuery = useQuery({
|
const selfQuery = useQuery({
|
||||||
@@ -162,7 +176,7 @@ export function CockpitView() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const stats = useMemo(() => {
|
const stats = useMemo(() => {
|
||||||
const list: AgentDeployment[] = deploymentsQuery.data ?? []
|
const list: AgentItem[] = deploymentsQuery.data ?? []
|
||||||
const counters: Record<StatusKey, number> = {
|
const counters: Record<StatusKey, number> = {
|
||||||
running: 0,
|
running: 0,
|
||||||
success: 0,
|
success: 0,
|
||||||
@@ -170,7 +184,7 @@ export function CockpitView() {
|
|||||||
pending: 0,
|
pending: 0,
|
||||||
}
|
}
|
||||||
list.forEach((d) => {
|
list.forEach((d) => {
|
||||||
counters[classifyStatus(d.display_status || d.status || '')]++
|
counters[classifyStatus(d.status || '')]++
|
||||||
})
|
})
|
||||||
const total = list.length || 1
|
const total = list.length || 1
|
||||||
const successRate = Math.round(
|
const successRate = Math.round(
|
||||||
@@ -254,7 +268,7 @@ export function CockpitView() {
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<Button asChild size='sm' variant='ghost' className='gap-1'>
|
<Button asChild size='sm' variant='ghost' className='gap-1'>
|
||||||
<Link to='/deployments'>
|
<Link to='/deploy-agent'>
|
||||||
{t('Open Deployments')}
|
{t('Open Deployments')}
|
||||||
<ArrowUpRight className='h-3.5 w-3.5' />
|
<ArrowUpRight className='h-3.5 w-3.5' />
|
||||||
</Link>
|
</Link>
|
||||||
@@ -276,47 +290,38 @@ export function CockpitView() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<ul className='space-y-2'>
|
<ul className='space-y-2'>
|
||||||
{recentDeployments.map((dep) => {
|
{recentDeployments.map((dep) => (
|
||||||
const tenant = dep.orchestration_plan?.metadata?.tenant_id || '—'
|
<li
|
||||||
const objective =
|
key={dep.agent_id}
|
||||||
dep.orchestration_plan?.objective ||
|
className='group flex items-center justify-between gap-4 rounded-xl border border-[color-mix(in_oklch,var(--primary)_18%,var(--border))] bg-[color-mix(in_oklch,var(--card)_55%,transparent)] p-3 transition hover:border-primary/45'
|
||||||
dep.orchestration_plan?.template_hint ||
|
>
|
||||||
t('No objective')
|
<div className='min-w-0 flex-1'>
|
||||||
return (
|
<div className='flex items-center gap-2'>
|
||||||
<li
|
<Rocket className='h-3.5 w-3.5 text-primary' />
|
||||||
key={dep.deployment_id}
|
<span className='truncate text-sm font-medium'>
|
||||||
className='group flex items-center justify-between gap-4 rounded-xl border border-[color-mix(in_oklch,var(--primary)_18%,var(--border))] bg-[color-mix(in_oklch,var(--card)_55%,transparent)] p-3 transition hover:border-primary/45'
|
{dep.template_id}
|
||||||
>
|
</span>
|
||||||
<div className='min-w-0 flex-1'>
|
<PhasePill phase={dep.status} />
|
||||||
<div className='flex items-center gap-2'>
|
|
||||||
<Rocket className='h-3.5 w-3.5 text-primary' />
|
|
||||||
<span className='truncate font-mono text-xs'>
|
|
||||||
{dep.deployment_id}
|
|
||||||
</span>
|
|
||||||
<PhasePill phase={dep.phase || dep.status} />
|
|
||||||
</div>
|
|
||||||
<p className='mt-1 truncate text-sm text-foreground/90'>
|
|
||||||
{objective}
|
|
||||||
</p>
|
|
||||||
<p className='mt-0.5 truncate text-[11px] text-muted-foreground'>
|
|
||||||
<Building2 className='mr-1 inline h-3 w-3' />
|
|
||||||
{tenant} · {formatRelative(dep.updated_at || dep.created_at)} ago
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<p className='mt-0.5 truncate text-[11px] text-muted-foreground'>
|
||||||
asChild
|
<Building2 className='mr-1 inline h-3 w-3' />
|
||||||
size='sm'
|
{dep.subdomain || '—'} ·{' '}
|
||||||
variant='outline'
|
{formatRelative(dep.updated_at || dep.created_at)} ago
|
||||||
className='shrink-0 opacity-70 group-hover:opacity-100'
|
</p>
|
||||||
>
|
</div>
|
||||||
<Link to='/deployments'>
|
<Button
|
||||||
<ScrollText className='mr-1 h-3.5 w-3.5' />
|
asChild
|
||||||
{t('Inspect')}
|
size='sm'
|
||||||
</Link>
|
variant='outline'
|
||||||
</Button>
|
className='shrink-0 opacity-70 group-hover:opacity-100'
|
||||||
</li>
|
>
|
||||||
)
|
<Link to='/deploy-agent'>
|
||||||
})}
|
<ScrollText className='mr-1 h-3.5 w-3.5' />
|
||||||
|
{t('Inspect')}
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,519 +0,0 @@
|
|||||||
/**
|
|
||||||
* Task Card route — implements docs/product-package/10 §"任务卡" + 11 §3
|
|
||||||
* 任务卡 wireframe, backed by mcp-server §6 HeicodeTask object:
|
|
||||||
*
|
|
||||||
* - status = "configuring" → render the open follow-up questions
|
|
||||||
* (each option becomes a clickable chip; clicking POSTs answer to
|
|
||||||
* /api/user/tasks/$id/answer and the backend state machine advances).
|
|
||||||
* - status = "running" / etc → render task.card with the four blocks
|
|
||||||
* the spec mandates: 目标 / 第一版范围 / 自动生成 / 待确认上下文.
|
|
||||||
*
|
|
||||||
* Forbidden per §10 高级展开: no JSON editor, no permission manifest, no
|
|
||||||
* resource_grant editor. Only the user-facing summary fields.
|
|
||||||
*/
|
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
|
||||||
import { Link, getRouteApi } from '@tanstack/react-router'
|
|
||||||
import {
|
|
||||||
ArrowLeft,
|
|
||||||
CheckCircle2,
|
|
||||||
CircleDashed,
|
|
||||||
GitBranch,
|
|
||||||
ListChecks,
|
|
||||||
MessageSquare,
|
|
||||||
PencilLine,
|
|
||||||
PlayCircle,
|
|
||||||
Rocket,
|
|
||||||
ScrollText,
|
|
||||||
ShieldCheck,
|
|
||||||
Sparkles,
|
|
||||||
Wallet,
|
|
||||||
XCircle,
|
|
||||||
} from 'lucide-react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { toast } from 'sonner'
|
|
||||||
import {
|
|
||||||
answerHeicodeTask,
|
|
||||||
createDeploymentDraftFromHeicodeTask,
|
|
||||||
getHeicodeTask,
|
|
||||||
type HeicodeFollowup,
|
|
||||||
type HeicodeManagerAction,
|
|
||||||
type HeicodeTask,
|
|
||||||
type HeicodeTaskStatus,
|
|
||||||
} from '@/lib/heicode-mcp'
|
|
||||||
import { cn } from '@/lib/utils'
|
|
||||||
import { Button } from '@/components/ui/button'
|
|
||||||
import { Skeleton } from '@/components/ui/skeleton'
|
|
||||||
import {
|
|
||||||
createAgentDeployment,
|
|
||||||
type AgentOrchestrationPlan,
|
|
||||||
} from '@/features/agent-console/api'
|
|
||||||
|
|
||||||
const route = getRouteApi('/_authenticated/tasks/$id')
|
|
||||||
|
|
||||||
type StatusKey = 'running' | 'success' | 'failed' | 'pending'
|
|
||||||
|
|
||||||
const STATUS_MAP: Record<HeicodeTaskStatus | string, StatusKey> = {
|
|
||||||
draft: 'pending',
|
|
||||||
configuring: 'pending',
|
|
||||||
awaiting_approval: 'pending',
|
|
||||||
running: 'running',
|
|
||||||
paused: 'pending',
|
|
||||||
completed: 'success',
|
|
||||||
failed: 'failed',
|
|
||||||
}
|
|
||||||
|
|
||||||
function classifyStatus(s: string): StatusKey {
|
|
||||||
return STATUS_MAP[s] ?? 'pending'
|
|
||||||
}
|
|
||||||
|
|
||||||
function StatusBadge({ status }: { status: HeicodeTaskStatus | string }) {
|
|
||||||
const k = classifyStatus(status)
|
|
||||||
const map: Record<StatusKey, { cls: string; Icon: typeof PlayCircle }> = {
|
|
||||||
running: {
|
|
||||||
cls: 'bg-[color-mix(in_oklch,var(--primary)_22%,transparent)] text-primary ring-primary/40',
|
|
||||||
Icon: PlayCircle,
|
|
||||||
},
|
|
||||||
success: {
|
|
||||||
cls: 'bg-emerald-500/15 text-emerald-400 ring-emerald-500/30',
|
|
||||||
Icon: CheckCircle2,
|
|
||||||
},
|
|
||||||
failed: {
|
|
||||||
cls: 'bg-rose-500/15 text-rose-400 ring-rose-500/30',
|
|
||||||
Icon: XCircle,
|
|
||||||
},
|
|
||||||
pending: {
|
|
||||||
cls: 'bg-amber-500/15 text-amber-400 ring-amber-500/30',
|
|
||||||
Icon: CircleDashed,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const p = map[k]
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
className={cn(
|
|
||||||
'inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-semibold tracking-[0.12em] uppercase ring-1 ring-inset',
|
|
||||||
p.cls
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<p.Icon className='h-3 w-3' />
|
|
||||||
{status}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function readScopeArray(card: HeicodeTask['card'], key: string): string[] {
|
|
||||||
if (!card) return []
|
|
||||||
const v = (card as Record<string, unknown>)[key]
|
|
||||||
if (Array.isArray(v))
|
|
||||||
return v.filter((x): x is string => typeof x === 'string')
|
|
||||||
if (typeof v === 'string' && v.trim()) return [v]
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
function readManagerActions(card: HeicodeTask['card']): HeicodeManagerAction[] {
|
|
||||||
if (!card) return []
|
|
||||||
const v = (card as Record<string, unknown>).manager_actions
|
|
||||||
if (!Array.isArray(v)) return []
|
|
||||||
return v
|
|
||||||
.filter(
|
|
||||||
(x): x is HeicodeManagerAction =>
|
|
||||||
typeof x === 'object' &&
|
|
||||||
x != null &&
|
|
||||||
typeof (x as Record<string, unknown>).label === 'string' &&
|
|
||||||
typeof (x as Record<string, unknown>).deeplink === 'string'
|
|
||||||
)
|
|
||||||
.slice(0, 6)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Resolve helper icon for a manager action by deeplink keyword. */
|
|
||||||
function iconForAction(deeplink: string): typeof GitBranch {
|
|
||||||
const k = deeplink.toLowerCase()
|
|
||||||
if (
|
|
||||||
k.includes('resource') ||
|
|
||||||
k.includes('preparation') ||
|
|
||||||
k.includes('sk-source')
|
|
||||||
)
|
|
||||||
return GitBranch
|
|
||||||
if (k.includes('audit')) return ShieldCheck
|
|
||||||
if (k.includes('wallet') || k.includes('budget')) return Wallet
|
|
||||||
if (k.includes('event') || k.includes('activity')) return ScrollText
|
|
||||||
return Rocket
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Manager-side route normalization. Legacy deep-links from older mcp-server
|
|
||||||
* payloads (resources / team / audit) now collapse to the live task overview;
|
|
||||||
* wallet keeps its own route. */
|
|
||||||
function normalizeDeeplink(deeplink: string): string {
|
|
||||||
return deeplink
|
|
||||||
.replace(/^\/manager\/resources/i, '/deployments')
|
|
||||||
.replace(/^\/manager\/team/i, '/deployments')
|
|
||||||
.replace(/^\/manager\/audit/i, '/deployments')
|
|
||||||
.replace(/^\/manager\/wallet/i, '/wallet')
|
|
||||||
.replace(/^\/manager\//i, '/')
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Collect open follow-ups from the most recent Heicode thread entry. */
|
|
||||||
function collectOpenFollowups(task: HeicodeTask): HeicodeFollowup[] {
|
|
||||||
for (let i = task.thread.length - 1; i >= 0; i--) {
|
|
||||||
const entry = task.thread[i]!
|
|
||||||
if (
|
|
||||||
entry.kind === 'heicode' &&
|
|
||||||
entry.followups &&
|
|
||||||
entry.followups.length > 0
|
|
||||||
) {
|
|
||||||
return entry.followups
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TaskCardView() {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const { id } = route.useParams()
|
|
||||||
const queryClient = useQueryClient()
|
|
||||||
|
|
||||||
const { data: task, isLoading } = useQuery({
|
|
||||||
queryKey: ['heicode', 'task', id],
|
|
||||||
queryFn: () => getHeicodeTask(id),
|
|
||||||
refetchInterval: (q) => {
|
|
||||||
const status = (q.state.data as HeicodeTask | undefined)?.status
|
|
||||||
if (status === 'completed' || status === 'failed') return false
|
|
||||||
if (status === 'running' || status === 'awaiting_approval') return 3_000
|
|
||||||
return 15_000
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const answerMutation = useMutation({
|
|
||||||
mutationFn: ({ qid, oid }: { qid: string; oid: string }) =>
|
|
||||||
answerHeicodeTask(id, qid, oid),
|
|
||||||
onSuccess: (updated) => {
|
|
||||||
queryClient.setQueryData(['heicode', 'task', id], updated)
|
|
||||||
void queryClient.invalidateQueries({
|
|
||||||
queryKey: ['heicode', 'tasks', 'recent'],
|
|
||||||
})
|
|
||||||
if (updated.status === 'running') {
|
|
||||||
toast.success(
|
|
||||||
t(
|
|
||||||
'All follow-ups answered. Heicode generated the recommendation summary.'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onError: (err) => {
|
|
||||||
toast.error(
|
|
||||||
err instanceof Error ? err.message : t('Failed to answer follow-up')
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const deploymentMutation = useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
if (!task) throw new Error('Task not found')
|
|
||||||
const draft = await createDeploymentDraftFromHeicodeTask(task, {
|
|
||||||
sub_mode: 'agile',
|
|
||||||
binding_scope: `task-${task.id}`,
|
|
||||||
role_templates: ['backend'],
|
|
||||||
default_model_id: 'claude-sonnet-4-6',
|
|
||||||
})
|
|
||||||
return createAgentDeployment({
|
|
||||||
orchestration_plan:
|
|
||||||
draft.orchestration_plan as unknown as AgentOrchestrationPlan,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
onSuccess: (deployment) => {
|
|
||||||
void queryClient.invalidateQueries({ queryKey: ['agent', 'deployments'] })
|
|
||||||
toast.success(
|
|
||||||
t('Manager deployment created', {
|
|
||||||
deployment_id: deployment.deployment_id,
|
|
||||||
}) as string
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onError: (err) => {
|
|
||||||
toast.error(
|
|
||||||
err instanceof Error ? err.message : t('Deployment request failed')
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return (
|
|
||||||
<div className='mx-auto max-w-3xl space-y-4 p-6'>
|
|
||||||
<Skeleton className='h-7 w-40' />
|
|
||||||
<Skeleton className='h-48 w-full rounded-2xl' />
|
|
||||||
<Skeleton className='h-32 w-full rounded-2xl' />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!task) {
|
|
||||||
return (
|
|
||||||
<div className='mx-auto max-w-3xl space-y-4 p-6'>
|
|
||||||
<Button asChild variant='ghost' size='sm' className='gap-1'>
|
|
||||||
<Link to='/dashboard/$section' params={{ section: 'overview' }}>
|
|
||||||
<ArrowLeft className='h-4 w-4' />
|
|
||||||
{t('Back to home')}
|
|
||||||
</Link>
|
|
||||||
</Button>
|
|
||||||
<div className='rounded-2xl border border-dashed border-[color-mix(in_oklch,var(--primary)_22%,var(--border))] p-10 text-center'>
|
|
||||||
<p className='text-muted-foreground text-sm'>
|
|
||||||
{t(
|
|
||||||
'Task not found. It may have been removed or was never created.'
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const openFollowups = collectOpenFollowups(task)
|
|
||||||
// Card shape per live mcp-server smoke test (§6.4 returns):
|
|
||||||
// { goal: string, scope: string[], generated_artifacts: string[],
|
|
||||||
// manager_actions: Array<{label, deeplink}> }
|
|
||||||
const objective =
|
|
||||||
(task.card &&
|
|
||||||
((task.card as Record<string, unknown>).goal as string | undefined)) ||
|
|
||||||
task.name ||
|
|
||||||
task.intent ||
|
|
||||||
t('No objective')
|
|
||||||
const firstVersionScope =
|
|
||||||
readScopeArray(task.card, 'scope').length > 0
|
|
||||||
? readScopeArray(task.card, 'scope')
|
|
||||||
: [task.intent || objective]
|
|
||||||
const autoGenerated =
|
|
||||||
readScopeArray(task.card, 'generated_artifacts').length > 0
|
|
||||||
? readScopeArray(task.card, 'generated_artifacts')
|
|
||||||
: [
|
|
||||||
t('Product brief'),
|
|
||||||
t('Prototype description'),
|
|
||||||
t('Development tasks'),
|
|
||||||
t('Check list'),
|
|
||||||
t('Deployment steps'),
|
|
||||||
]
|
|
||||||
const managerActions = readManagerActions(task.card)
|
|
||||||
const pendingContextLine = t(
|
|
||||||
'Code, docs, cloud resources and high-risk approval rules. Connect them in the preparation checklist.'
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='mx-auto max-w-4xl space-y-5 p-6'>
|
|
||||||
<header className='flex items-center justify-between gap-3'>
|
|
||||||
<Button asChild variant='ghost' size='sm' className='gap-1'>
|
|
||||||
<Link to='/dashboard/$section' params={{ section: 'overview' }}>
|
|
||||||
<ArrowLeft className='h-4 w-4' />
|
|
||||||
{t('Back to home')}
|
|
||||||
</Link>
|
|
||||||
</Button>
|
|
||||||
<span className='text-muted-foreground font-mono text-[11px]'>
|
|
||||||
{task.id}
|
|
||||||
</span>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{/* ── Follow-up questions (only while status=configuring) ─────────── */}
|
|
||||||
{task.status === 'configuring' && openFollowups.length > 0 && (
|
|
||||||
<section
|
|
||||||
className='overflow-hidden rounded-3xl border p-5 sm:p-6'
|
|
||||||
style={{
|
|
||||||
borderColor: 'rgba(123,107,227,0.28)',
|
|
||||||
backgroundImage:
|
|
||||||
'linear-gradient(180deg, rgba(123,107,227,0.07) 0%, rgba(123,107,227,0.00) 60%)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className='flex items-start gap-3'>
|
|
||||||
<span
|
|
||||||
className='inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-2xl text-white'
|
|
||||||
style={{ backgroundImage: 'var(--gradient-brand)' }}
|
|
||||||
>
|
|
||||||
<MessageSquare className='h-4 w-4' />
|
|
||||||
</span>
|
|
||||||
<div className='min-w-0 flex-1'>
|
|
||||||
<p className='text-muted-foreground text-[11px] font-semibold tracking-[0.16em] uppercase'>
|
|
||||||
{t('Heicode is asking')}
|
|
||||||
</p>
|
|
||||||
<p className='text-foreground mt-1 text-sm'>
|
|
||||||
{task.status_caption ||
|
|
||||||
t(
|
|
||||||
'Answer a few questions so Heicode can draft the right plan.'
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ol className='mt-5 space-y-4'>
|
|
||||||
{openFollowups.map((q) => (
|
|
||||||
<li
|
|
||||||
key={q.id}
|
|
||||||
className='bg-background/40 rounded-2xl border border-[color-mix(in_oklch,var(--primary)_18%,var(--border))] p-4'
|
|
||||||
>
|
|
||||||
<p className='text-sm font-medium'>{q.question}</p>
|
|
||||||
<div className='mt-3 flex flex-wrap gap-2'>
|
|
||||||
{q.options.map((opt) => (
|
|
||||||
<Button
|
|
||||||
key={opt.id}
|
|
||||||
type='button'
|
|
||||||
size='sm'
|
|
||||||
variant='outline'
|
|
||||||
disabled={answerMutation.isPending}
|
|
||||||
onClick={() =>
|
|
||||||
answerMutation.mutate({ qid: q.id, oid: opt.id })
|
|
||||||
}
|
|
||||||
className={cn(
|
|
||||||
'rounded-xl text-xs',
|
|
||||||
opt.risk === 'high-risk' &&
|
|
||||||
'border-rose-500/40 text-rose-300 hover:border-rose-500/70'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{opt.label}
|
|
||||||
{opt.risk === 'high-risk' && (
|
|
||||||
<span className='ms-1 rounded-full bg-rose-500/15 px-1.5 text-[9px] tracking-wider text-rose-300 uppercase'>
|
|
||||||
{t('high-risk')}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ol>
|
|
||||||
</section>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* ── Task card (objective / scope / auto / pending) ───────────── */}
|
|
||||||
<section
|
|
||||||
className='overflow-hidden rounded-3xl border p-6 sm:p-8'
|
|
||||||
style={{
|
|
||||||
borderColor: 'rgba(123,107,227,0.28)',
|
|
||||||
backgroundImage:
|
|
||||||
'radial-gradient(circle at 0% 0%, rgba(184,136,229,0.10), transparent 60%), linear-gradient(180deg, rgba(123,107,227,0.04) 0%, rgba(123,107,227,0.00) 60%)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className='flex items-start justify-between gap-4'>
|
|
||||||
<div className='min-w-0 flex-1'>
|
|
||||||
<p className='text-muted-foreground text-[11px] font-semibold tracking-[0.16em] uppercase'>
|
|
||||||
{t('Task card')}
|
|
||||||
</p>
|
|
||||||
<h1 className='mt-2 text-2xl font-semibold tracking-tight sm:text-3xl'>
|
|
||||||
{objective}
|
|
||||||
</h1>
|
|
||||||
{task.intent && task.intent !== objective && (
|
|
||||||
<p className='text-muted-foreground mt-2 text-sm'>
|
|
||||||
{task.intent}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<StatusBadge status={task.status} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='mt-6 grid gap-5 md:grid-cols-2'>
|
|
||||||
<div className='bg-background/40 rounded-2xl border border-[color-mix(in_oklch,var(--primary)_18%,var(--border))] p-4'>
|
|
||||||
<p className='flex items-center gap-1.5 text-sm font-semibold'>
|
|
||||||
<ListChecks className='text-primary h-4 w-4' />
|
|
||||||
{t('First-version scope')}
|
|
||||||
</p>
|
|
||||||
<ul className='text-muted-foreground mt-2 space-y-1.5 text-sm'>
|
|
||||||
{firstVersionScope.map((line, i) => (
|
|
||||||
<li key={i} className='flex items-start gap-2'>
|
|
||||||
<span className='bg-primary mt-1.5 inline-block h-1 w-1 shrink-0 rounded-full' />
|
|
||||||
<span>{line}</span>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='bg-background/40 rounded-2xl border border-[color-mix(in_oklch,var(--primary)_18%,var(--border))] p-4'>
|
|
||||||
<p className='flex items-center gap-1.5 text-sm font-semibold'>
|
|
||||||
<Sparkles className='text-primary h-4 w-4' />
|
|
||||||
{t('Heicode auto-generates')}
|
|
||||||
</p>
|
|
||||||
<p className='text-muted-foreground mt-2 text-sm'>
|
|
||||||
{autoGenerated.join(' / ')}
|
|
||||||
</p>
|
|
||||||
<p className='text-muted-foreground mt-2 text-[11px]'>
|
|
||||||
{t(
|
|
||||||
'These artifacts appear inside the desktop client as the task progresses.'
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='bg-background/30 mt-5 rounded-2xl border border-dashed border-[color-mix(in_oklch,var(--primary)_22%,var(--border))] p-4'>
|
|
||||||
<p className='text-muted-foreground text-[11px] font-semibold tracking-[0.14em] uppercase'>
|
|
||||||
{t('Needs Manager assistance')}
|
|
||||||
</p>
|
|
||||||
<div className='mt-3 flex flex-wrap gap-2'>
|
|
||||||
{managerActions.length > 0 ? (
|
|
||||||
managerActions.map((act) => {
|
|
||||||
const Icon = iconForAction(act.deeplink)
|
|
||||||
const to = normalizeDeeplink(act.deeplink).split('?')[0]
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
key={`${act.label}-${act.deeplink}`}
|
|
||||||
asChild
|
|
||||||
size='sm'
|
|
||||||
variant='outline'
|
|
||||||
className='rounded-xl'
|
|
||||||
>
|
|
||||||
<a href={to}>
|
|
||||||
<Icon className='mr-1 h-3.5 w-3.5' />
|
|
||||||
{act.label}
|
|
||||||
</a>
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
asChild
|
|
||||||
size='sm'
|
|
||||||
variant='outline'
|
|
||||||
className='rounded-xl'
|
|
||||||
>
|
|
||||||
<Link to='/wallet'>
|
|
||||||
<Wallet className='mr-1 h-3.5 w-3.5' />
|
|
||||||
{t('Budget & usage')}
|
|
||||||
</Link>
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer className='mt-6 flex flex-wrap items-center justify-between gap-3 border-t border-dashed border-[color-mix(in_oklch,var(--primary)_18%,var(--border))] pt-4'>
|
|
||||||
<Button
|
|
||||||
variant='ghost'
|
|
||||||
size='sm'
|
|
||||||
className='text-muted-foreground gap-1'
|
|
||||||
disabled
|
|
||||||
title={t('Editing the objective happens in the desktop client.')}
|
|
||||||
>
|
|
||||||
<PencilLine className='h-3.5 w-3.5' />
|
|
||||||
{t('Edit objective in desktop client')}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type='button'
|
|
||||||
variant='outline'
|
|
||||||
size='sm'
|
|
||||||
className='gap-1 rounded-xl'
|
|
||||||
disabled={
|
|
||||||
deploymentMutation.isPending ||
|
|
||||||
task.status === 'failed' ||
|
|
||||||
task.status === 'draft' ||
|
|
||||||
task.status === 'configuring'
|
|
||||||
}
|
|
||||||
onClick={() => deploymentMutation.mutate()}
|
|
||||||
>
|
|
||||||
<Rocket className='h-3.5 w-3.5' />
|
|
||||||
{deploymentMutation.isPending
|
|
||||||
? t('Creating deployment')
|
|
||||||
: t('Create Manager deployment')}
|
|
||||||
</Button>
|
|
||||||
</footer>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className='rounded-2xl border border-[color-mix(in_oklch,var(--primary)_18%,var(--border))] bg-[color-mix(in_oklch,var(--card)_55%,transparent)] p-4'>
|
|
||||||
<p className='text-muted-foreground text-[11px] font-semibold tracking-[0.16em] uppercase'>
|
|
||||||
{t('Pending context')}
|
|
||||||
</p>
|
|
||||||
<p className='text-muted-foreground mt-2 text-sm'>
|
|
||||||
{pendingContextLine}
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -40,7 +40,6 @@ const DEFAULT_SIDEBAR_MODULES: SidebarModulesAdminConfig = {
|
|||||||
const URL_TO_CONFIG_MAP: Record<string, { section: string; module: string }> = {
|
const URL_TO_CONFIG_MAP: Record<string, { section: string; module: string }> = {
|
||||||
'/dashboard': { section: 'cockpit', module: 'overview' },
|
'/dashboard': { section: 'cockpit', module: 'overview' },
|
||||||
'/dashboard/overview': { section: 'cockpit', module: 'overview' },
|
'/dashboard/overview': { section: 'cockpit', module: 'overview' },
|
||||||
'/deployments': { section: 'cockpit', module: 'deployments' },
|
|
||||||
'/users': { section: 'admin', module: 'tenants' },
|
'/users': { section: 'admin', module: 'tenants' },
|
||||||
'/system-settings/general': { section: 'admin', module: 'settings' },
|
'/system-settings/general': { section: 'admin', module: 'settings' },
|
||||||
'/system-settings': { section: 'admin', module: 'settings' },
|
'/system-settings': { section: 'admin', module: 'settings' },
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
Download,
|
Download,
|
||||||
GitBranch,
|
GitBranch,
|
||||||
LayoutDashboard,
|
LayoutDashboard,
|
||||||
Rocket,
|
|
||||||
Settings,
|
Settings,
|
||||||
Smartphone,
|
Smartphone,
|
||||||
UserCog,
|
UserCog,
|
||||||
@@ -58,11 +57,6 @@ export function useSidebarData(): SidebarData {
|
|||||||
url: '/deploy-agent',
|
url: '/deploy-agent',
|
||||||
icon: Bot,
|
icon: Bot,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: t('Agent runs'),
|
|
||||||
url: '/deployments',
|
|
||||||
icon: Rocket,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -63,8 +63,5 @@ export function useTopNavLinks(): TopNavLink[] {
|
|||||||
if (modules?.overview !== false) {
|
if (modules?.overview !== false) {
|
||||||
links.push({ title: t('Overview'), href: '/dashboard' })
|
links.push({ title: t('Overview'), href: '/dashboard' })
|
||||||
}
|
}
|
||||||
if (modules?.deployments !== false) {
|
|
||||||
links.push({ title: t('Deployments'), href: '/deployments' })
|
|
||||||
}
|
|
||||||
return links
|
return links
|
||||||
}
|
}
|
||||||
|
|||||||
-43
@@ -45,13 +45,11 @@ import { Route as AuthenticatedModelsIndexRouteImport } from './routes/_authenti
|
|||||||
import { Route as AuthenticatedKeysIndexRouteImport } from './routes/_authenticated/keys/index'
|
import { Route as AuthenticatedKeysIndexRouteImport } from './routes/_authenticated/keys/index'
|
||||||
import { Route as AuthenticatedDevicesIndexRouteImport } from './routes/_authenticated/devices/index'
|
import { Route as AuthenticatedDevicesIndexRouteImport } from './routes/_authenticated/devices/index'
|
||||||
import { Route as AuthenticatedDesktopClientIndexRouteImport } from './routes/_authenticated/desktop-client/index'
|
import { Route as AuthenticatedDesktopClientIndexRouteImport } from './routes/_authenticated/desktop-client/index'
|
||||||
import { Route as AuthenticatedDeploymentsIndexRouteImport } from './routes/_authenticated/deployments/index'
|
|
||||||
import { Route as AuthenticatedDeployAgentIndexRouteImport } from './routes/_authenticated/deploy-agent/index'
|
import { Route as AuthenticatedDeployAgentIndexRouteImport } from './routes/_authenticated/deploy-agent/index'
|
||||||
import { Route as AuthenticatedDashboardIndexRouteImport } from './routes/_authenticated/dashboard/index'
|
import { Route as AuthenticatedDashboardIndexRouteImport } from './routes/_authenticated/dashboard/index'
|
||||||
import { Route as AuthenticatedChannelsIndexRouteImport } from './routes/_authenticated/channels/index'
|
import { Route as AuthenticatedChannelsIndexRouteImport } from './routes/_authenticated/channels/index'
|
||||||
import { Route as AuthenticatedAvailableModelsIndexRouteImport } from './routes/_authenticated/available-models/index'
|
import { Route as AuthenticatedAvailableModelsIndexRouteImport } from './routes/_authenticated/available-models/index'
|
||||||
import { Route as AuthenticatedUsageLogsSectionRouteImport } from './routes/_authenticated/usage-logs/$section'
|
import { Route as AuthenticatedUsageLogsSectionRouteImport } from './routes/_authenticated/usage-logs/$section'
|
||||||
import { Route as AuthenticatedTasksIdRouteImport } from './routes/_authenticated/tasks/$id'
|
|
||||||
import { Route as AuthenticatedModelsSectionRouteImport } from './routes/_authenticated/models/$section'
|
import { Route as AuthenticatedModelsSectionRouteImport } from './routes/_authenticated/models/$section'
|
||||||
import { Route as AuthenticatedErrorsErrorRouteImport } from './routes/_authenticated/errors/$error'
|
import { Route as AuthenticatedErrorsErrorRouteImport } from './routes/_authenticated/errors/$error'
|
||||||
import { Route as AuthenticatedDashboardSectionRouteImport } from './routes/_authenticated/dashboard/$section'
|
import { Route as AuthenticatedDashboardSectionRouteImport } from './routes/_authenticated/dashboard/$section'
|
||||||
@@ -262,12 +260,6 @@ const AuthenticatedDesktopClientIndexRoute =
|
|||||||
path: '/desktop-client/',
|
path: '/desktop-client/',
|
||||||
getParentRoute: () => AuthenticatedRouteRoute,
|
getParentRoute: () => AuthenticatedRouteRoute,
|
||||||
} as any)
|
} as any)
|
||||||
const AuthenticatedDeploymentsIndexRoute =
|
|
||||||
AuthenticatedDeploymentsIndexRouteImport.update({
|
|
||||||
id: '/deployments/',
|
|
||||||
path: '/deployments/',
|
|
||||||
getParentRoute: () => AuthenticatedRouteRoute,
|
|
||||||
} as any)
|
|
||||||
const AuthenticatedDeployAgentIndexRoute =
|
const AuthenticatedDeployAgentIndexRoute =
|
||||||
AuthenticatedDeployAgentIndexRouteImport.update({
|
AuthenticatedDeployAgentIndexRouteImport.update({
|
||||||
id: '/deploy-agent/',
|
id: '/deploy-agent/',
|
||||||
@@ -298,11 +290,6 @@ const AuthenticatedUsageLogsSectionRoute =
|
|||||||
path: '/usage-logs/$section',
|
path: '/usage-logs/$section',
|
||||||
getParentRoute: () => AuthenticatedRouteRoute,
|
getParentRoute: () => AuthenticatedRouteRoute,
|
||||||
} as any)
|
} as any)
|
||||||
const AuthenticatedTasksIdRoute = AuthenticatedTasksIdRouteImport.update({
|
|
||||||
id: '/tasks/$id',
|
|
||||||
path: '/tasks/$id',
|
|
||||||
getParentRoute: () => AuthenticatedRouteRoute,
|
|
||||||
} as any)
|
|
||||||
const AuthenticatedModelsSectionRoute =
|
const AuthenticatedModelsSectionRoute =
|
||||||
AuthenticatedModelsSectionRouteImport.update({
|
AuthenticatedModelsSectionRouteImport.update({
|
||||||
id: '/models/$section',
|
id: '/models/$section',
|
||||||
@@ -442,13 +429,11 @@ export interface FileRoutesByFullPath {
|
|||||||
'/dashboard/$section': typeof AuthenticatedDashboardSectionRoute
|
'/dashboard/$section': typeof AuthenticatedDashboardSectionRoute
|
||||||
'/errors/$error': typeof AuthenticatedErrorsErrorRoute
|
'/errors/$error': typeof AuthenticatedErrorsErrorRoute
|
||||||
'/models/$section': typeof AuthenticatedModelsSectionRoute
|
'/models/$section': typeof AuthenticatedModelsSectionRoute
|
||||||
'/tasks/$id': typeof AuthenticatedTasksIdRoute
|
|
||||||
'/usage-logs/$section': typeof AuthenticatedUsageLogsSectionRoute
|
'/usage-logs/$section': typeof AuthenticatedUsageLogsSectionRoute
|
||||||
'/available-models/': typeof AuthenticatedAvailableModelsIndexRoute
|
'/available-models/': typeof AuthenticatedAvailableModelsIndexRoute
|
||||||
'/channels/': typeof AuthenticatedChannelsIndexRoute
|
'/channels/': typeof AuthenticatedChannelsIndexRoute
|
||||||
'/dashboard/': typeof AuthenticatedDashboardIndexRoute
|
'/dashboard/': typeof AuthenticatedDashboardIndexRoute
|
||||||
'/deploy-agent/': typeof AuthenticatedDeployAgentIndexRoute
|
'/deploy-agent/': typeof AuthenticatedDeployAgentIndexRoute
|
||||||
'/deployments/': typeof AuthenticatedDeploymentsIndexRoute
|
|
||||||
'/desktop-client/': typeof AuthenticatedDesktopClientIndexRoute
|
'/desktop-client/': typeof AuthenticatedDesktopClientIndexRoute
|
||||||
'/devices/': typeof AuthenticatedDevicesIndexRoute
|
'/devices/': typeof AuthenticatedDevicesIndexRoute
|
||||||
'/keys/': typeof AuthenticatedKeysIndexRoute
|
'/keys/': typeof AuthenticatedKeysIndexRoute
|
||||||
@@ -503,13 +488,11 @@ export interface FileRoutesByTo {
|
|||||||
'/dashboard/$section': typeof AuthenticatedDashboardSectionRoute
|
'/dashboard/$section': typeof AuthenticatedDashboardSectionRoute
|
||||||
'/errors/$error': typeof AuthenticatedErrorsErrorRoute
|
'/errors/$error': typeof AuthenticatedErrorsErrorRoute
|
||||||
'/models/$section': typeof AuthenticatedModelsSectionRoute
|
'/models/$section': typeof AuthenticatedModelsSectionRoute
|
||||||
'/tasks/$id': typeof AuthenticatedTasksIdRoute
|
|
||||||
'/usage-logs/$section': typeof AuthenticatedUsageLogsSectionRoute
|
'/usage-logs/$section': typeof AuthenticatedUsageLogsSectionRoute
|
||||||
'/available-models': typeof AuthenticatedAvailableModelsIndexRoute
|
'/available-models': typeof AuthenticatedAvailableModelsIndexRoute
|
||||||
'/channels': typeof AuthenticatedChannelsIndexRoute
|
'/channels': typeof AuthenticatedChannelsIndexRoute
|
||||||
'/dashboard': typeof AuthenticatedDashboardIndexRoute
|
'/dashboard': typeof AuthenticatedDashboardIndexRoute
|
||||||
'/deploy-agent': typeof AuthenticatedDeployAgentIndexRoute
|
'/deploy-agent': typeof AuthenticatedDeployAgentIndexRoute
|
||||||
'/deployments': typeof AuthenticatedDeploymentsIndexRoute
|
|
||||||
'/desktop-client': typeof AuthenticatedDesktopClientIndexRoute
|
'/desktop-client': typeof AuthenticatedDesktopClientIndexRoute
|
||||||
'/devices': typeof AuthenticatedDevicesIndexRoute
|
'/devices': typeof AuthenticatedDevicesIndexRoute
|
||||||
'/keys': typeof AuthenticatedKeysIndexRoute
|
'/keys': typeof AuthenticatedKeysIndexRoute
|
||||||
@@ -568,13 +551,11 @@ export interface FileRoutesById {
|
|||||||
'/_authenticated/dashboard/$section': typeof AuthenticatedDashboardSectionRoute
|
'/_authenticated/dashboard/$section': typeof AuthenticatedDashboardSectionRoute
|
||||||
'/_authenticated/errors/$error': typeof AuthenticatedErrorsErrorRoute
|
'/_authenticated/errors/$error': typeof AuthenticatedErrorsErrorRoute
|
||||||
'/_authenticated/models/$section': typeof AuthenticatedModelsSectionRoute
|
'/_authenticated/models/$section': typeof AuthenticatedModelsSectionRoute
|
||||||
'/_authenticated/tasks/$id': typeof AuthenticatedTasksIdRoute
|
|
||||||
'/_authenticated/usage-logs/$section': typeof AuthenticatedUsageLogsSectionRoute
|
'/_authenticated/usage-logs/$section': typeof AuthenticatedUsageLogsSectionRoute
|
||||||
'/_authenticated/available-models/': typeof AuthenticatedAvailableModelsIndexRoute
|
'/_authenticated/available-models/': typeof AuthenticatedAvailableModelsIndexRoute
|
||||||
'/_authenticated/channels/': typeof AuthenticatedChannelsIndexRoute
|
'/_authenticated/channels/': typeof AuthenticatedChannelsIndexRoute
|
||||||
'/_authenticated/dashboard/': typeof AuthenticatedDashboardIndexRoute
|
'/_authenticated/dashboard/': typeof AuthenticatedDashboardIndexRoute
|
||||||
'/_authenticated/deploy-agent/': typeof AuthenticatedDeployAgentIndexRoute
|
'/_authenticated/deploy-agent/': typeof AuthenticatedDeployAgentIndexRoute
|
||||||
'/_authenticated/deployments/': typeof AuthenticatedDeploymentsIndexRoute
|
|
||||||
'/_authenticated/desktop-client/': typeof AuthenticatedDesktopClientIndexRoute
|
'/_authenticated/desktop-client/': typeof AuthenticatedDesktopClientIndexRoute
|
||||||
'/_authenticated/devices/': typeof AuthenticatedDevicesIndexRoute
|
'/_authenticated/devices/': typeof AuthenticatedDevicesIndexRoute
|
||||||
'/_authenticated/keys/': typeof AuthenticatedKeysIndexRoute
|
'/_authenticated/keys/': typeof AuthenticatedKeysIndexRoute
|
||||||
@@ -632,13 +613,11 @@ export interface FileRouteTypes {
|
|||||||
| '/dashboard/$section'
|
| '/dashboard/$section'
|
||||||
| '/errors/$error'
|
| '/errors/$error'
|
||||||
| '/models/$section'
|
| '/models/$section'
|
||||||
| '/tasks/$id'
|
|
||||||
| '/usage-logs/$section'
|
| '/usage-logs/$section'
|
||||||
| '/available-models/'
|
| '/available-models/'
|
||||||
| '/channels/'
|
| '/channels/'
|
||||||
| '/dashboard/'
|
| '/dashboard/'
|
||||||
| '/deploy-agent/'
|
| '/deploy-agent/'
|
||||||
| '/deployments/'
|
|
||||||
| '/desktop-client/'
|
| '/desktop-client/'
|
||||||
| '/devices/'
|
| '/devices/'
|
||||||
| '/keys/'
|
| '/keys/'
|
||||||
@@ -693,13 +672,11 @@ export interface FileRouteTypes {
|
|||||||
| '/dashboard/$section'
|
| '/dashboard/$section'
|
||||||
| '/errors/$error'
|
| '/errors/$error'
|
||||||
| '/models/$section'
|
| '/models/$section'
|
||||||
| '/tasks/$id'
|
|
||||||
| '/usage-logs/$section'
|
| '/usage-logs/$section'
|
||||||
| '/available-models'
|
| '/available-models'
|
||||||
| '/channels'
|
| '/channels'
|
||||||
| '/dashboard'
|
| '/dashboard'
|
||||||
| '/deploy-agent'
|
| '/deploy-agent'
|
||||||
| '/deployments'
|
|
||||||
| '/desktop-client'
|
| '/desktop-client'
|
||||||
| '/devices'
|
| '/devices'
|
||||||
| '/keys'
|
| '/keys'
|
||||||
@@ -757,13 +734,11 @@ export interface FileRouteTypes {
|
|||||||
| '/_authenticated/dashboard/$section'
|
| '/_authenticated/dashboard/$section'
|
||||||
| '/_authenticated/errors/$error'
|
| '/_authenticated/errors/$error'
|
||||||
| '/_authenticated/models/$section'
|
| '/_authenticated/models/$section'
|
||||||
| '/_authenticated/tasks/$id'
|
|
||||||
| '/_authenticated/usage-logs/$section'
|
| '/_authenticated/usage-logs/$section'
|
||||||
| '/_authenticated/available-models/'
|
| '/_authenticated/available-models/'
|
||||||
| '/_authenticated/channels/'
|
| '/_authenticated/channels/'
|
||||||
| '/_authenticated/dashboard/'
|
| '/_authenticated/dashboard/'
|
||||||
| '/_authenticated/deploy-agent/'
|
| '/_authenticated/deploy-agent/'
|
||||||
| '/_authenticated/deployments/'
|
|
||||||
| '/_authenticated/desktop-client/'
|
| '/_authenticated/desktop-client/'
|
||||||
| '/_authenticated/devices/'
|
| '/_authenticated/devices/'
|
||||||
| '/_authenticated/keys/'
|
| '/_authenticated/keys/'
|
||||||
@@ -1066,13 +1041,6 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof AuthenticatedDesktopClientIndexRouteImport
|
preLoaderRoute: typeof AuthenticatedDesktopClientIndexRouteImport
|
||||||
parentRoute: typeof AuthenticatedRouteRoute
|
parentRoute: typeof AuthenticatedRouteRoute
|
||||||
}
|
}
|
||||||
'/_authenticated/deployments/': {
|
|
||||||
id: '/_authenticated/deployments/'
|
|
||||||
path: '/deployments'
|
|
||||||
fullPath: '/deployments/'
|
|
||||||
preLoaderRoute: typeof AuthenticatedDeploymentsIndexRouteImport
|
|
||||||
parentRoute: typeof AuthenticatedRouteRoute
|
|
||||||
}
|
|
||||||
'/_authenticated/deploy-agent/': {
|
'/_authenticated/deploy-agent/': {
|
||||||
id: '/_authenticated/deploy-agent/'
|
id: '/_authenticated/deploy-agent/'
|
||||||
path: '/deploy-agent'
|
path: '/deploy-agent'
|
||||||
@@ -1108,13 +1076,6 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof AuthenticatedUsageLogsSectionRouteImport
|
preLoaderRoute: typeof AuthenticatedUsageLogsSectionRouteImport
|
||||||
parentRoute: typeof AuthenticatedRouteRoute
|
parentRoute: typeof AuthenticatedRouteRoute
|
||||||
}
|
}
|
||||||
'/_authenticated/tasks/$id': {
|
|
||||||
id: '/_authenticated/tasks/$id'
|
|
||||||
path: '/tasks/$id'
|
|
||||||
fullPath: '/tasks/$id'
|
|
||||||
preLoaderRoute: typeof AuthenticatedTasksIdRouteImport
|
|
||||||
parentRoute: typeof AuthenticatedRouteRoute
|
|
||||||
}
|
|
||||||
'/_authenticated/models/$section': {
|
'/_authenticated/models/$section': {
|
||||||
id: '/_authenticated/models/$section'
|
id: '/_authenticated/models/$section'
|
||||||
path: '/models/$section'
|
path: '/models/$section'
|
||||||
@@ -1339,13 +1300,11 @@ interface AuthenticatedRouteRouteChildren {
|
|||||||
AuthenticatedDashboardSectionRoute: typeof AuthenticatedDashboardSectionRoute
|
AuthenticatedDashboardSectionRoute: typeof AuthenticatedDashboardSectionRoute
|
||||||
AuthenticatedErrorsErrorRoute: typeof AuthenticatedErrorsErrorRoute
|
AuthenticatedErrorsErrorRoute: typeof AuthenticatedErrorsErrorRoute
|
||||||
AuthenticatedModelsSectionRoute: typeof AuthenticatedModelsSectionRoute
|
AuthenticatedModelsSectionRoute: typeof AuthenticatedModelsSectionRoute
|
||||||
AuthenticatedTasksIdRoute: typeof AuthenticatedTasksIdRoute
|
|
||||||
AuthenticatedUsageLogsSectionRoute: typeof AuthenticatedUsageLogsSectionRoute
|
AuthenticatedUsageLogsSectionRoute: typeof AuthenticatedUsageLogsSectionRoute
|
||||||
AuthenticatedAvailableModelsIndexRoute: typeof AuthenticatedAvailableModelsIndexRoute
|
AuthenticatedAvailableModelsIndexRoute: typeof AuthenticatedAvailableModelsIndexRoute
|
||||||
AuthenticatedChannelsIndexRoute: typeof AuthenticatedChannelsIndexRoute
|
AuthenticatedChannelsIndexRoute: typeof AuthenticatedChannelsIndexRoute
|
||||||
AuthenticatedDashboardIndexRoute: typeof AuthenticatedDashboardIndexRoute
|
AuthenticatedDashboardIndexRoute: typeof AuthenticatedDashboardIndexRoute
|
||||||
AuthenticatedDeployAgentIndexRoute: typeof AuthenticatedDeployAgentIndexRoute
|
AuthenticatedDeployAgentIndexRoute: typeof AuthenticatedDeployAgentIndexRoute
|
||||||
AuthenticatedDeploymentsIndexRoute: typeof AuthenticatedDeploymentsIndexRoute
|
|
||||||
AuthenticatedDesktopClientIndexRoute: typeof AuthenticatedDesktopClientIndexRoute
|
AuthenticatedDesktopClientIndexRoute: typeof AuthenticatedDesktopClientIndexRoute
|
||||||
AuthenticatedDevicesIndexRoute: typeof AuthenticatedDevicesIndexRoute
|
AuthenticatedDevicesIndexRoute: typeof AuthenticatedDevicesIndexRoute
|
||||||
AuthenticatedKeysIndexRoute: typeof AuthenticatedKeysIndexRoute
|
AuthenticatedKeysIndexRoute: typeof AuthenticatedKeysIndexRoute
|
||||||
@@ -1368,14 +1327,12 @@ const AuthenticatedRouteRouteChildren: AuthenticatedRouteRouteChildren = {
|
|||||||
AuthenticatedDashboardSectionRoute: AuthenticatedDashboardSectionRoute,
|
AuthenticatedDashboardSectionRoute: AuthenticatedDashboardSectionRoute,
|
||||||
AuthenticatedErrorsErrorRoute: AuthenticatedErrorsErrorRoute,
|
AuthenticatedErrorsErrorRoute: AuthenticatedErrorsErrorRoute,
|
||||||
AuthenticatedModelsSectionRoute: AuthenticatedModelsSectionRoute,
|
AuthenticatedModelsSectionRoute: AuthenticatedModelsSectionRoute,
|
||||||
AuthenticatedTasksIdRoute: AuthenticatedTasksIdRoute,
|
|
||||||
AuthenticatedUsageLogsSectionRoute: AuthenticatedUsageLogsSectionRoute,
|
AuthenticatedUsageLogsSectionRoute: AuthenticatedUsageLogsSectionRoute,
|
||||||
AuthenticatedAvailableModelsIndexRoute:
|
AuthenticatedAvailableModelsIndexRoute:
|
||||||
AuthenticatedAvailableModelsIndexRoute,
|
AuthenticatedAvailableModelsIndexRoute,
|
||||||
AuthenticatedChannelsIndexRoute: AuthenticatedChannelsIndexRoute,
|
AuthenticatedChannelsIndexRoute: AuthenticatedChannelsIndexRoute,
|
||||||
AuthenticatedDashboardIndexRoute: AuthenticatedDashboardIndexRoute,
|
AuthenticatedDashboardIndexRoute: AuthenticatedDashboardIndexRoute,
|
||||||
AuthenticatedDeployAgentIndexRoute: AuthenticatedDeployAgentIndexRoute,
|
AuthenticatedDeployAgentIndexRoute: AuthenticatedDeployAgentIndexRoute,
|
||||||
AuthenticatedDeploymentsIndexRoute: AuthenticatedDeploymentsIndexRoute,
|
|
||||||
AuthenticatedDesktopClientIndexRoute: AuthenticatedDesktopClientIndexRoute,
|
AuthenticatedDesktopClientIndexRoute: AuthenticatedDesktopClientIndexRoute,
|
||||||
AuthenticatedDevicesIndexRoute: AuthenticatedDevicesIndexRoute,
|
AuthenticatedDevicesIndexRoute: AuthenticatedDevicesIndexRoute,
|
||||||
AuthenticatedKeysIndexRoute: AuthenticatedKeysIndexRoute,
|
AuthenticatedKeysIndexRoute: AuthenticatedKeysIndexRoute,
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router'
|
|
||||||
import { AgentDeploymentsPage } from '@/features/agent-console/pages'
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/_authenticated/deployments/')({
|
|
||||||
component: AgentDeploymentsPage,
|
|
||||||
})
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router'
|
|
||||||
import { TaskCardView } from '@/features/tasks/task-card-view'
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/_authenticated/tasks/$id')({
|
|
||||||
component: TaskCardView,
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user