refactor(ui): adopt PageHeader on agent/media/import/backend pages (batch A)

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Assisted-by: Claude:claude-opus-4-8 [Claude Code]
This commit is contained in:
Ettore Di Giacinto
2026-06-18 14:56:56 +00:00
parent a24cc84f7d
commit f1132f9143
15 changed files with 163 additions and 178 deletions

View File

@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'
import { useAuth } from '../context/AuthContext'
import { apiKeysApi, profileApi } from '../utils/api'
import LoadingSpinner from '../components/LoadingSpinner'
import PageHeader from '../components/PageHeader'
import SettingRow from '../components/SettingRow'
import ConfirmDialog from '../components/ConfirmDialog'
import './auth.css'
@@ -452,10 +453,7 @@ export default function Account() {
return (
<div className="page page--narrow account-page">
{/* Header */}
<div className="page-header">
<h1 className="page-title">{t('account.title')}</h1>
<p className="page-subtitle">{t('account.subtitle')}</p>
</div>
<PageHeader title={t('account.title')} supporting={t('account.subtitle')} />
{/* Tab bar */}
<div className="auth-tab-bar auth-tab-bar--flush">

View File

@@ -2,6 +2,7 @@ import { useState, useEffect, useMemo } from 'react'
import { useParams, useNavigate, useLocation, useOutletContext, useSearchParams } from 'react-router-dom'
import { agentsApi, skillsApi } from '../utils/api'
import SearchableModelSelect from '../components/SearchableModelSelect'
import PageHeader from '../components/PageHeader'
import { CAP_CHAT, CAP_TRANSCRIPT, CAP_TTS } from '../utils/capabilities'
import Toggle from '../components/Toggle'
import SettingRow from '../components/SettingRow'
@@ -930,12 +931,14 @@ export default function AgentCreate() {
}
`}</style>
<div className="page-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<h1 className="page-title">{isEdit ? `Edit Agent: ${name}` : importedConfig ? 'Import Agent' : 'Create Agent'}</h1>
<button className="btn btn-secondary btn-sm" onClick={() => navigate('/app/agents')}>
<i className="fas fa-arrow-left" /> Back
</button>
</div>
<PageHeader
title={isEdit ? `Edit Agent: ${name}` : importedConfig ? 'Import Agent' : 'Create Agent'}
actions={
<button className="btn btn-secondary btn-sm" onClick={() => navigate('/app/agents')}>
<i className="fas fa-arrow-left" /> Back
</button>
}
/>
<form onSubmit={handleSubmit} noValidate>
<div className="agent-form-container">

View File

@@ -2,6 +2,7 @@ import { useState, useEffect, useRef } from 'react'
import { useParams, useNavigate, useOutletContext } from 'react-router-dom'
import { agentJobsApi } from '../utils/api'
import LoadingSpinner from '../components/LoadingSpinner'
import PageHeader from '../components/PageHeader'
const traceColors = {
reasoning: { bg: 'rgba(99,102,241,0.1)', border: 'rgba(99,102,241,0.3)', icon: 'fa-brain', color: 'var(--color-primary)' },
@@ -178,22 +179,22 @@ export default function AgentJobDetails() {
return (
<div className="page page--narrow">
<div className="page-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<h1 className="page-title">Job Details</h1>
<p className="page-subtitle">Live status and reasoning traces</p>
</div>
<div style={{ display: 'flex', gap: 'var(--spacing-sm)' }}>
{(job.status === 'running' || job.status === 'pending') && (
<button className="btn btn-danger" onClick={handleCancel}>
<i className="fas fa-stop" /> Cancel
<PageHeader
title="Job Details"
supporting="Live status and reasoning traces"
actions={
<div style={{ display: 'flex', gap: 'var(--spacing-sm)' }}>
{(job.status === 'running' || job.status === 'pending') && (
<button className="btn btn-danger" onClick={handleCancel}>
<i className="fas fa-stop" /> Cancel
</button>
)}
<button className="btn btn-secondary" onClick={() => navigate('/app/agent-jobs')}>
<i className="fas fa-arrow-left" /> Back
</button>
)}
<button className="btn btn-secondary" onClick={() => navigate('/app/agent-jobs')}>
<i className="fas fa-arrow-left" /> Back
</button>
</div>
</div>
</div>
}
/>
{/* Status Card */}
<div className="card" style={{ marginBottom: 'var(--spacing-md)' }}>

View File

@@ -6,6 +6,7 @@ import { useModels } from '../hooks/useModels'
import { useAuth } from '../context/AuthContext'
import { useUserMap } from '../hooks/useUserMap'
import LoadingSpinner from '../components/LoadingSpinner'
import PageHeader from '../components/PageHeader'
import { fileToBase64 } from '../utils/api'
import Modal from '../components/Modal'
import UserGroupSection from '../components/UserGroupSection'
@@ -216,10 +217,7 @@ export default function AgentJobs() {
if (!loading && models.length === 0) {
return (
<div className="page page--wide">
<div className="page-header">
<h1 className="page-title">Agent Jobs</h1>
<p className="page-subtitle">Manage agent tasks and automated workflows</p>
</div>
<PageHeader title="Agent Jobs" supporting="Manage agent tasks and automated workflows" />
<div className="card" style={{ textAlign: 'center', padding: 'var(--spacing-xl)' }}>
<i className="fas fa-exclamation-triangle" style={{ fontSize: '3rem', color: 'var(--color-warning)', marginBottom: 'var(--spacing-md)' }} />
<h2 style={{ marginBottom: 'var(--spacing-sm)' }}>No Models Installed</h2>
@@ -243,10 +241,7 @@ export default function AgentJobs() {
if (!loading && models.length > 0 && !hasMCPModels && tasks.length === 0) {
return (
<div className="page page--wide">
<div className="page-header">
<h1 className="page-title">Agent Jobs</h1>
<p className="page-subtitle">Manage agent tasks and automated workflows</p>
</div>
<PageHeader title="Agent Jobs" supporting="Manage agent tasks and automated workflows" />
<div className="card" style={{ textAlign: 'center', padding: 'var(--spacing-xl)' }}>
<i className="fas fa-plug" style={{ fontSize: '3rem', color: 'var(--color-primary)', marginBottom: 'var(--spacing-md)' }} />
<h2 style={{ marginBottom: 'var(--spacing-sm)' }}>MCP Not Configured</h2>
@@ -276,15 +271,15 @@ export default function AgentJobs() {
return (
<div className="page page--wide">
<div className="page-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<h1 className="page-title">Agent Jobs</h1>
<p className="page-subtitle">Manage agent tasks and automated workflows</p>
</div>
<button className="btn btn-primary" onClick={() => navigate('/app/agent-jobs/tasks/new')}>
<i className="fas fa-plus" /> New Task
</button>
</div>
<PageHeader
title="Agent Jobs"
supporting="Manage agent tasks and automated workflows"
actions={
<button className="btn btn-primary" onClick={() => navigate('/app/agent-jobs/tasks/new')}>
<i className="fas fa-plus" /> New Task
</button>
}
/>
<div className="tabs">
<button className={`tab ${activeTab === 'tasks' ? 'tab-active' : ''}`} onClick={() => setActiveTab('tasks')}>

View File

@@ -2,6 +2,7 @@ import { useState, useEffect, useCallback } from 'react'
import { useParams, useNavigate, useOutletContext, useSearchParams } from 'react-router-dom'
import { agentsApi } from '../utils/api'
import { apiUrl } from '../utils/basePath'
import PageHeader from '../components/PageHeader'
function ObservableSummary({ observable }) {
const creation = observable?.creation || {}
@@ -352,29 +353,26 @@ export default function AgentStatus() {
.as-status-value { font-size: 1rem; font-weight: 600; color: var(--color-text-primary); }
`}</style>
<div className="page-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<h1 className="page-title">
<i className="fas fa-chart-bar" style={{ marginRight: 'var(--spacing-xs)' }} />
{name} Status
</h1>
<p className="page-subtitle">Agent observables and activity history</p>
</div>
<div style={{ display: 'flex', gap: 'var(--spacing-sm)' }}>
<button className="btn btn-secondary" onClick={() => navigate(`/app/agents/${encodeURIComponent(name)}/chat${userId ? `?user_id=${encodeURIComponent(userId)}` : ''}`)}>
<i className="fas fa-comment" /> Chat
</button>
<button className="btn btn-secondary" onClick={() => navigate(`/app/agents/${encodeURIComponent(name)}/edit${userId ? `?user_id=${encodeURIComponent(userId)}` : ''}`)}>
<i className="fas fa-edit" /> Edit
</button>
<button className="btn btn-secondary" onClick={fetchData}>
<i className="fas fa-sync" /> Refresh
</button>
<button className="btn btn-danger" onClick={handleClear} disabled={observables.length === 0}>
<i className="fas fa-trash" /> Clear
</button>
</div>
</div>
<PageHeader
title={<><i className="fas fa-chart-bar" style={{ marginRight: 'var(--spacing-xs)' }} />{name} Status</>}
supporting="Agent observables and activity history"
actions={
<div style={{ display: 'flex', gap: 'var(--spacing-sm)' }}>
<button className="btn btn-secondary" onClick={() => navigate(`/app/agents/${encodeURIComponent(name)}/chat${userId ? `?user_id=${encodeURIComponent(userId)}` : ''}`)}>
<i className="fas fa-comment" /> Chat
</button>
<button className="btn btn-secondary" onClick={() => navigate(`/app/agents/${encodeURIComponent(name)}/edit${userId ? `?user_id=${encodeURIComponent(userId)}` : ''}`)}>
<i className="fas fa-edit" /> Edit
</button>
<button className="btn btn-secondary" onClick={fetchData}>
<i className="fas fa-sync" /> Refresh
</button>
<button className="btn btn-danger" onClick={handleClear} disabled={observables.length === 0}>
<i className="fas fa-trash" /> Clear
</button>
</div>
}
/>
{/* Status summary */}
{status && (

View File

@@ -3,6 +3,7 @@ import { useParams, useNavigate, useOutletContext, useLocation } from 'react-rou
import { agentJobsApi } from '../utils/api'
import { basePath } from '../utils/basePath'
import ModelSelector from '../components/ModelSelector'
import PageHeader from '../components/PageHeader'
import { CAP_CHAT } from '../utils/capabilities'
import LoadingSpinner from '../components/LoadingSpinner'
@@ -165,20 +166,20 @@ export default function AgentTaskDetails() {
if (!isNew && !isEdit) {
return (
<div className="page page--narrow">
<div className="page-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<h1 className="page-title">{task.name || 'Task Details'}</h1>
{task.description && <p className="page-subtitle">{task.description}</p>}
</div>
<div style={{ display: 'flex', gap: 'var(--spacing-sm)' }}>
<button className="btn btn-primary btn-sm" onClick={() => navigate(`/app/agent-jobs/tasks/${id}/edit`)}>
<i className="fas fa-edit" /> Edit
</button>
<button className="btn btn-secondary btn-sm" onClick={() => navigate('/app/agent-jobs')}>
<i className="fas fa-arrow-left" /> Back
</button>
</div>
</div>
<PageHeader
title={task.name || 'Task Details'}
supporting={task.description || undefined}
actions={
<div style={{ display: 'flex', gap: 'var(--spacing-sm)' }}>
<button className="btn btn-primary btn-sm" onClick={() => navigate(`/app/agent-jobs/tasks/${id}/edit`)}>
<i className="fas fa-edit" /> Edit
</button>
<button className="btn btn-secondary btn-sm" onClick={() => navigate('/app/agent-jobs')}>
<i className="fas fa-arrow-left" /> Back
</button>
</div>
}
/>
{/* Task Info */}
<div className="card" style={{ marginBottom: 'var(--spacing-md)' }}>
@@ -307,12 +308,14 @@ export default function AgentTaskDetails() {
// Edit/Create form
return (
<div className="page page--narrow">
<div className="page-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<h1 className="page-title">{isNew ? 'Create Task' : 'Edit Task'}</h1>
<button className="btn btn-secondary btn-sm" onClick={() => navigate('/app/agent-jobs')}>
<i className="fas fa-arrow-left" /> Back
</button>
</div>
<PageHeader
title={isNew ? 'Create Task' : 'Edit Task'}
actions={
<button className="btn btn-secondary btn-sm" onClick={() => navigate('/app/agent-jobs')}>
<i className="fas fa-arrow-left" /> Back
</button>
}
/>
<form onSubmit={handleSave}>
{/* Basic Info */}

View File

@@ -5,6 +5,7 @@ import { agentsApi } from '../utils/api'
import { useAuth } from '../context/AuthContext'
import { useUserMap } from '../hooks/useUserMap'
import UserGroupSection from '../components/UserGroupSection'
import PageHeader from '../components/PageHeader'
import ConfirmDialog from '../components/ConfirmDialog'
export default function Agents() {
@@ -181,26 +182,26 @@ export default function Agents() {
}
`}</style>
<div className="page-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<h1 className="page-title">{t('title')}</h1>
<p className="page-subtitle">{t('subtitle')}</p>
</div>
<div style={{ display: 'flex', gap: 'var(--spacing-sm)', alignItems: 'center' }}>
{agentHubURL && (
<a className="btn btn-secondary" href={agentHubURL} target="_blank" rel="noopener noreferrer">
<i className="fas fa-store" /> {t('actions.agentHub')}
</a>
)}
<label className="btn btn-secondary">
<i className="fas fa-file-import" /> {t('actions.import')}
<input type="file" accept=".json" className="agents-import-input" onChange={handleImport} />
</label>
<button className="btn btn-primary" onClick={() => navigate('/app/agents/new')}>
<i className="fas fa-plus" /> {t('actions.createAgent')}
</button>
</div>
</div>
<PageHeader
title={t('title')}
supporting={t('subtitle')}
actions={
<div style={{ display: 'flex', gap: 'var(--spacing-sm)', alignItems: 'center' }}>
{agentHubURL && (
<a className="btn btn-secondary" href={agentHubURL} target="_blank" rel="noopener noreferrer">
<i className="fas fa-store" /> {t('actions.agentHub')}
</a>
)}
<label className="btn btn-secondary">
<i className="fas fa-file-import" /> {t('actions.import')}
<input type="file" accept=".json" className="agents-import-input" onChange={handleImport} />
</label>
<button className="btn btn-primary" onClick={() => navigate('/app/agents/new')}>
<i className="fas fa-plus" /> {t('actions.createAgent')}
</button>
</div>
}
/>
{loading ? (
<div style={{ display: 'flex', justifyContent: 'center', padding: 'var(--spacing-xl)' }}>

View File

@@ -1,6 +1,7 @@
import { useState, useEffect, useRef } from 'react'
import { useParams, useOutletContext } from 'react-router-dom'
import ModelSelector from '../components/ModelSelector'
import PageHeader from '../components/PageHeader'
import { CAP_AUDIO_TRANSFORM } from '../utils/capabilities'
import LoadingSpinner from '../components/LoadingSpinner'
import ErrorWithTraceLink from '../components/ErrorWithTraceLink'
@@ -166,9 +167,7 @@ export default function AudioTransform() {
return (
<div className="media-layout">
<div className="media-controls">
<div className="page-header">
<h1 className="page-title"><i className="fas fa-wave-square" /> Audio Transform</h1>
</div>
<PageHeader title={<><i className="fas fa-wave-square" /> Audio Transform</>} />
<form onSubmit={handleProcess}>
<div className="form-group">

View File

@@ -4,6 +4,7 @@ import { backendLogsApi, nodesApi } from '../utils/api'
import { formatTimestamp } from '../utils/format'
import { apiUrl } from '../utils/basePath'
import LoadingSpinner from '../components/LoadingSpinner'
import PageHeader from '../components/PageHeader'
import { useDistributedMode } from '../hooks/useDistributedMode'
function wsUrl(path) {
@@ -151,15 +152,10 @@ function BackendLogsDetail({ modelId }) {
return (
<div className="page page--wide">
<div className="page-header">
<div>
<h1 className="page-title" style={{ marginBottom: 0 }}>
<i className="fas fa-terminal" style={{ fontSize: '0.8em', marginRight: 'var(--spacing-sm)' }} />
{modelId}
</h1>
<p className="page-subtitle" style={{ marginTop: 'var(--spacing-xs)' }}>Backend process output</p>
</div>
</div>
<PageHeader
title={<><i className="fas fa-terminal" style={{ fontSize: '0.8em', marginRight: 'var(--spacing-sm)' }} />{modelId}</>}
supporting="Backend process output"
/>
{/* Toolbar */}
<div style={{ display: 'flex', gap: 'var(--spacing-sm)', marginBottom: 'var(--spacing-md)', alignItems: 'center', flexWrap: 'wrap' }}>
@@ -361,17 +357,10 @@ function DistributedBackendLogsResolver({ modelId, fromTimestamp }) {
// Multiple workers host this model — let the operator pick.
return (
<div className="page page--wide">
<div className="page-header">
<div>
<h1 className="page-title" style={{ marginBottom: 0 }}>
<i className="fas fa-terminal" style={{ fontSize: '0.8em', marginRight: 'var(--spacing-sm)' }} />
{modelId}
</h1>
<p className="page-subtitle" style={{ marginTop: 'var(--spacing-xs)' }}>
Hosted on {hits.length} workers — pick one to view its logs.
</p>
</div>
</div>
<PageHeader
title={<><i className="fas fa-terminal" style={{ fontSize: '0.8em', marginRight: 'var(--spacing-sm)' }} />{modelId}</>}
supporting={`Hosted on ${hits.length} workers — pick one to view its logs.`}
/>
<div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-xs)' }}>
{hits.map(({ node, model }) => (
<Link

View File

@@ -7,6 +7,7 @@ import React from 'react'
import { useOperations } from '../hooks/useOperations'
import { useDistributedMode } from '../hooks/useDistributedMode'
import LoadingSpinner from '../components/LoadingSpinner'
import PageHeader from '../components/PageHeader'
import { renderMarkdown } from '../utils/markdown'
import { safeHref } from '../utils/url'
import ConfirmDialog from '../components/ConfirmDialog'
@@ -348,11 +349,10 @@ export default function Backends() {
)}
{/* Header */}
<div className="page-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
<div>
<h1 className="page-title">{t('backends.title')}</h1>
<p className="page-subtitle">{t('backends.subtitle')}</p>
</div>
<PageHeader
title={t('backends.title')}
supporting={t('backends.subtitle')}
actions={
<div style={{ display: 'flex', gap: 'var(--spacing-md)', alignItems: 'center' }}>
<div style={{ display: 'flex', gap: 'var(--spacing-md)', fontSize: '0.8125rem' }}>
<div style={{ textAlign: 'center' }}>
@@ -378,7 +378,8 @@ export default function Backends() {
<i className="fas fa-book" /> Docs
</a>
</div>
</div>
}
/>
{/* Upgrade Banner */}
{Object.keys(upgrades).length > 0 && (

View File

@@ -2,6 +2,7 @@ import { useState, useEffect, useCallback } from 'react'
import { useParams, useOutletContext, useSearchParams } from 'react-router-dom'
import { agentCollectionsApi } from '../utils/api'
import ConfirmDialog from '../components/ConfirmDialog'
import PageHeader from '../components/PageHeader'
export default function CollectionDetails() {
const { name } = useParams()
@@ -292,10 +293,7 @@ export default function CollectionDetails() {
}
`}</style>
<div className="page-header">
<h1 className="page-title">{name}</h1>
<p className="page-subtitle">Collection details and management</p>
</div>
<PageHeader title={name} supporting="Collection details and management" />
<div className="tabs">
<button className={`tab ${activeTab === 'entries' ? 'tab-active' : ''}`} onClick={() => setActiveTab('entries')}>

View File

@@ -5,6 +5,7 @@ import { agentCollectionsApi } from '../utils/api'
import { useAuth } from '../context/AuthContext'
import { useUserMap } from '../hooks/useUserMap'
import UserGroupSection from '../components/UserGroupSection'
import PageHeader from '../components/PageHeader'
import ConfirmDialog from '../components/ConfirmDialog'
export default function Collections() {
@@ -119,10 +120,7 @@ export default function Collections() {
}
`}</style>
<div className="page-header">
<h1 className="page-title">{t('title')}</h1>
<p className="page-subtitle">{t('subtitle')}</p>
</div>
<PageHeader title={t('title')} supporting={t('subtitle')} />
<div className="collections-create-bar">
<input

View File

@@ -1,6 +1,7 @@
import { useState, useEffect, useRef, useCallback } from 'react'
import { fineTuneApi } from '../utils/api'
import LoadingSpinner from '../components/LoadingSpinner'
import PageHeader from '../components/PageHeader'
const TRAINING_METHODS = ['sft', 'dpo', 'grpo', 'rloo', 'reward', 'kto', 'orpo']
const TRAINING_TYPES = ['lora', 'loha', 'lokr', 'full']
@@ -1058,21 +1059,21 @@ export default function FineTune() {
return (
<div className="page page--wide">
<div className="page-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
<div>
<h1 className="page-title">Fine-Tuning <span className="badge badge-warning" style={{ fontSize: '0.45em', verticalAlign: 'middle' }}>Experimental</span></h1>
<p className="page-subtitle">Create and manage fine-tuning jobs</p>
</div>
<div style={{ display: 'flex', gap: 'var(--spacing-sm)' }}>
<button className="btn" onClick={handleImportConfig}>
<i className="fas fa-upload" style={{ marginRight: 'var(--spacing-xs)' }} /> Import Config
</button>
<button className="btn btn-primary" onClick={() => setShowForm(!showForm)}>
<i className={`fas fa-${showForm ? 'times' : 'plus'}`} style={{ marginRight: 'var(--spacing-xs)' }} />
{showForm ? 'Cancel' : 'New Job'}
</button>
</div>
</div>
<PageHeader
title={<>Fine-Tuning <span className="badge badge-warning" style={{ fontSize: '0.45em', verticalAlign: 'middle' }}>Experimental</span></>}
supporting="Create and manage fine-tuning jobs"
actions={
<div style={{ display: 'flex', gap: 'var(--spacing-sm)' }}>
<button className="btn" onClick={handleImportConfig}>
<i className="fas fa-upload" style={{ marginRight: 'var(--spacing-xs)' }} /> Import Config
</button>
<button className="btn btn-primary" onClick={() => setShowForm(!showForm)}>
<i className={`fas fa-${showForm ? 'times' : 'plus'}`} style={{ marginRight: 'var(--spacing-xs)' }} />
{showForm ? 'Cancel' : 'New Job'}
</button>
</div>
}
/>
{error && (
<div className="card" style={{ background: 'var(--color-error-light)', borderColor: 'var(--color-error-border)', color: 'var(--color-error)', marginBottom: 'var(--spacing-md)', padding: 'var(--spacing-md)' }}>

View File

@@ -2,6 +2,7 @@ import { useState, useRef } from 'react'
import { useParams, useOutletContext } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import ModelSelector from '../components/ModelSelector'
import PageHeader from '../components/PageHeader'
import { CAP_IMAGE } from '../utils/capabilities'
import LoadingSpinner from '../components/LoadingSpinner'
import ErrorWithTraceLink from '../components/ErrorWithTraceLink'
@@ -84,9 +85,7 @@ export default function ImageGen() {
return (
<div className="media-layout">
<div className="media-controls">
<div className="page-header">
<h1 className="page-title"><i className="fas fa-image" /> {t('image.title')}</h1>
</div>
<PageHeader title={<><i className="fas fa-image" /> {t('image.title')}</>} />
<form onSubmit={handleGenerate}>
<div className="form-group">

View File

@@ -3,6 +3,7 @@ import { useNavigate, useOutletContext } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import { modelsApi, backendsApi } from '../utils/api'
import LoadingSpinner from '../components/LoadingSpinner'
import PageHeader from '../components/PageHeader'
import CodeEditor from '../components/CodeEditor'
import SearchableSelect from '../components/SearchableSelect'
import AmbiguityAlert from '../components/AmbiguityAlert'
@@ -798,24 +799,24 @@ export default function ImportModel() {
return (
<div className="page page--narrow">
<div className="page-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 'var(--spacing-sm)' }}>
<div>
<h1 className="page-title">{t('title')}</h1>
<p className="page-subtitle">{subtitle}</p>
</div>
<div style={{ display: 'flex', gap: 'var(--spacing-sm)', flexWrap: 'wrap', alignItems: 'center' }}>
<SimplePowerSwitch value={mode} onChange={requestModeSwitch} disabled={isSubmitting} />
{isPowerYaml ? (
<button className="btn btn-primary" onClick={handleAdvancedImport} disabled={isSubmitting}>
{isSubmitting ? <><LoadingSpinner size="sm" /> {t('actions.saving')}</> : <><i className="fas fa-save" aria-hidden="true" /> {t('actions.create')}</>}
</button>
) : (
<button className="btn btn-primary" onClick={() => handleSimpleImport()} disabled={isSubmitting || !importUri.trim()}>
{isSubmitting ? <><LoadingSpinner size="sm" /> {t('actions.importing')}</> : <><i className="fas fa-upload" aria-hidden="true" /> {t('actions.import')}</>}
</button>
)}
</div>
</div>
<PageHeader
title={t('title')}
supporting={subtitle}
actions={
<div style={{ display: 'flex', gap: 'var(--spacing-sm)', flexWrap: 'wrap', alignItems: 'center' }}>
<SimplePowerSwitch value={mode} onChange={requestModeSwitch} disabled={isSubmitting} />
{isPowerYaml ? (
<button className="btn btn-primary" onClick={handleAdvancedImport} disabled={isSubmitting}>
{isSubmitting ? <><LoadingSpinner size="sm" /> {t('actions.saving')}</> : <><i className="fas fa-save" aria-hidden="true" /> {t('actions.create')}</>}
</button>
) : (
<button className="btn btn-primary" onClick={() => handleSimpleImport()} disabled={isSubmitting || !importUri.trim()}>
{isSubmitting ? <><LoadingSpinner size="sm" /> {t('actions.importing')}</> : <><i className="fas fa-upload" aria-hidden="true" /> {t('actions.import')}</>}
</button>
)}
</div>
}
/>
{/* Estimate banner */}
{!isPowerYaml && estimate && (