fix: add missing REJECTED and DELETION values to config_status enum

Root cause: config_status enum was created with only PENDING and APPLIED
values. The REJECTED value was never added due to a silent duplicate_object
exception in create_essential_tables(). This caused SSL certificate listing
to crash with "invalid input value for enum config_status: REJECTED" on
fresh installations.

Also adds scrollable containers to Apply Management page to prevent
Agent Sync Status card from being pushed off-screen.

Closes #7

Made-with: Cursor
This commit is contained in:
taylanbakircioglu
2026-04-01 12:45:31 +03:00
parent 922bc2ce6d
commit 77bd3ecead
2 changed files with 98 additions and 88 deletions
+4
View File
@@ -45,6 +45,10 @@ async def ensure_agents_table():
await conn.execute("CREATE TYPE config_status AS ENUM ('PENDING', 'APPLIED');")
logger.info("Successfully created config_status enum type.")
await conn.execute("ALTER TYPE config_status ADD VALUE IF NOT EXISTS 'REJECTED';")
await conn.execute("ALTER TYPE config_status ADD VALUE IF NOT EXISTS 'DELETION';")
logger.info("Ensured REJECTED and DELETION values exist in config_status enum.")
# First, create essential tables if they don't exist
await create_essential_tables(conn)
+94 -88
View File
@@ -1243,39 +1243,41 @@ const ApplyManagement = () => {
{/* Pending Versions Section */}
{pendingVersions.length > 0 && (
<div style={{ marginBottom: 24 }}>
<Title level={5}>
<div style={{ marginBottom: 24, background: '#fffbe6', borderRadius: 8, border: '1px solid #ffe58f', padding: '16px 16px 8px' }}>
<Title level={5} style={{ marginTop: 0 }}>
<ClockCircleOutlined style={{ marginRight: 8, color: '#faad14' }} />
Pending Changes ({pendingVersions.length})
</Title>
<Timeline size="small">
{pendingVersions.map((version, index) => (
<Timeline.Item
key={version.id}
color="orange"
dot={<ClockCircleOutlined style={{ color: '#faad14' }} />}
>
<div style={{ fontSize: 12 }}>
<div style={{ fontWeight: 'bold', marginBottom: 4 }}>{version.version_name}</div>
<div style={{ color: '#666', marginBottom: 8 }}>
{new Date(version.created_at).toLocaleString()}
<div style={{ maxHeight: 240, overflowY: 'auto', paddingRight: 8 }}>
<Timeline size="small">
{pendingVersions.map((version, index) => (
<Timeline.Item
key={version.id}
color="orange"
dot={<ClockCircleOutlined style={{ color: '#faad14' }} />}
>
<div style={{ fontSize: 12 }}>
<div style={{ fontWeight: 'bold', marginBottom: 4 }}>{version.version_name}</div>
<div style={{ color: '#666', marginBottom: 8 }}>
{new Date(version.created_at).toLocaleString()}
</div>
<div style={{ marginBottom: 4 }}>
<Tag color="orange" size="small">PENDING</Tag>
</div>
<Button
type="link"
size="small"
icon={<EyeOutlined />}
onClick={() => handleViewChange(version)}
style={{ padding: 0, height: 'auto', fontSize: 11 }}
>
View Change
</Button>
</div>
<div style={{ marginBottom: 4 }}>
<Tag color="orange" size="small">PENDING</Tag>
</div>
<Button
type="link"
size="small"
icon={<EyeOutlined />}
onClick={() => handleViewChange(version)}
style={{ padding: 0, height: 'auto', fontSize: 11 }}
>
View Change
</Button>
</div>
</Timeline.Item>
))}
</Timeline>
</Timeline.Item>
))}
</Timeline>
</div>
</div>
)}
@@ -1298,31 +1300,33 @@ const ApplyManagement = () => {
style={{ margin: '20px 0' }}
/>
) : (
<Timeline size="small">
{appliedVersions.map((version, index) => (
<Timeline.Item
key={version.id}
color={index === 0 ? 'green' : 'gray'}
dot={index === 0 ? <CheckCircleOutlined style={{ color: '#52c41a' }} /> : undefined}
>
<div style={{ fontSize: 12 }}>
<div style={{ fontWeight: 'bold', marginBottom: 4 }}>{version.version_name}</div>
<div style={{ color: '#666', marginBottom: 8 }}>
{new Date(version.created_at).toLocaleString()}
<div style={{ maxHeight: 420, overflowY: 'auto', paddingRight: 8 }}>
<Timeline size="small">
{appliedVersions.map((version, index) => (
<Timeline.Item
key={version.id}
color={index === 0 ? 'green' : 'gray'}
dot={index === 0 ? <CheckCircleOutlined style={{ color: '#52c41a' }} /> : undefined}
>
<div style={{ fontSize: 12 }}>
<div style={{ fontWeight: 'bold', marginBottom: 4 }}>{version.version_name}</div>
<div style={{ color: '#666', marginBottom: 8 }}>
{new Date(version.created_at).toLocaleString()}
</div>
<Button
type="link"
size="small"
icon={<EyeOutlined />}
onClick={() => handleViewChange(version)}
style={{ padding: 0, height: 'auto', fontSize: 11 }}
>
View Change
</Button>
</div>
<Button
type="link"
size="small"
icon={<EyeOutlined />}
onClick={() => handleViewChange(version)}
style={{ padding: 0, height: 'auto', fontSize: 11 }}
>
View Change
</Button>
</div>
</Timeline.Item>
))}
</Timeline>
</Timeline.Item>
))}
</Timeline>
</div>
)}
</TabPane>
@@ -1343,42 +1347,44 @@ const ApplyManagement = () => {
style={{ margin: '20px 0' }}
/>
) : (
<Timeline size="small">
{rejectedVersions.map((version, index) => (
<Timeline.Item
key={version.id}
color="red"
dot={<CloseCircleOutlined style={{ color: '#ff4d4f' }} />}
>
<div style={{ fontSize: 12 }}>
<div style={{ fontWeight: 'bold', marginBottom: 4 }}>{version.version_name}</div>
<div style={{ color: '#666', marginBottom: 8 }}>
Rejected: {new Date(version.updated_at || version.created_at).toLocaleString()}
<div style={{ maxHeight: 420, overflowY: 'auto', paddingRight: 8 }}>
<Timeline size="small">
{rejectedVersions.map((version, index) => (
<Timeline.Item
key={version.id}
color="red"
dot={<CloseCircleOutlined style={{ color: '#ff4d4f' }} />}
>
<div style={{ fontSize: 12 }}>
<div style={{ fontWeight: 'bold', marginBottom: 4 }}>{version.version_name}</div>
<div style={{ color: '#666', marginBottom: 8 }}>
Rejected: {new Date(version.updated_at || version.created_at).toLocaleString()}
</div>
<Space size="small">
<Button
type="link"
size="small"
icon={<EyeOutlined />}
onClick={() => handleViewChange(version)}
style={{ padding: 0, height: 'auto', fontSize: 11 }}
>
View Changes
</Button>
<Button
type="link"
size="small"
icon={<UndoOutlined />}
onClick={() => handleUndoRejected(version)}
style={{ padding: 0, height: 'auto', fontSize: 11, color: '#1890ff' }}
>
Undo
</Button>
</Space>
</div>
<Space size="small">
<Button
type="link"
size="small"
icon={<EyeOutlined />}
onClick={() => handleViewChange(version)}
style={{ padding: 0, height: 'auto', fontSize: 11 }}
>
View Changes
</Button>
<Button
type="link"
size="small"
icon={<UndoOutlined />}
onClick={() => handleUndoRejected(version)}
style={{ padding: 0, height: 'auto', fontSize: 11, color: '#1890ff' }}
>
Undo
</Button>
</Space>
</div>
</Timeline.Item>
))}
</Timeline>
</Timeline.Item>
))}
</Timeline>
</div>
)}
</TabPane>
</Tabs>