feat: visually distinguish digital-twin linked tenants
All checks were successful
Deploy to Production / deploy (push) Successful in 2m2s
All checks were successful
Deploy to Production / deploy (push) Successful in 2m2s
- Add has_digital_twin flag to tenant API response - Show cloud badge on tenant card for linked tenants - Hide sync/import buttons for tenants without mapping - Add .tenant-badge-dt CSS for the badge
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState, useCallback, useMemo } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { useMachines } from '@/lib/hooks';
|
||||
import { useMachines, useTenants } from '@/lib/hooks';
|
||||
import { useToast } from '@/lib/toast-context';
|
||||
import { api } from '@/lib/api';
|
||||
import { MachineList } from '@/components/MachineList';
|
||||
@@ -36,7 +36,10 @@ export default function TenantDashboard() {
|
||||
const router = useRouter();
|
||||
const tenantId = params?.tenant as string;
|
||||
const { machines, isLoading, error, mutate } = useMachines(tenantId);
|
||||
const { tenants } = useTenants();
|
||||
const { addToast } = useToast();
|
||||
const currentTenant = tenants.find(t => t.id === tenantId);
|
||||
const hasDigitalTwin = currentTenant?.has_digital_twin ?? false;
|
||||
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [form, setForm] = useState<MachineForm>(INITIAL_FORM);
|
||||
@@ -270,14 +273,18 @@ export default function TenantDashboard() {
|
||||
설비 관리
|
||||
</h2>
|
||||
<div className="page-header-actions">
|
||||
<button className={`btn-sync ${syncing ? 'sync-spinning' : ''}`} onClick={handleSync} disabled={syncing}>
|
||||
<span className="material-symbols-outlined">sync</span>
|
||||
동기화
|
||||
</button>
|
||||
<button className="btn-outline" onClick={openImportModal}>
|
||||
<span className="material-symbols-outlined">cloud_download</span>
|
||||
디지털 트윈에서 가져오기
|
||||
</button>
|
||||
{hasDigitalTwin && (
|
||||
<>
|
||||
<button className={`btn-sync ${syncing ? 'sync-spinning' : ''}`} onClick={handleSync} disabled={syncing}>
|
||||
<span className="material-symbols-outlined">sync</span>
|
||||
동기화
|
||||
</button>
|
||||
<button className="btn-outline" onClick={openImportModal}>
|
||||
<span className="material-symbols-outlined">cloud_download</span>
|
||||
디지털 트윈에서 가져오기
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
<button className="btn-primary" onClick={openCreate}>
|
||||
<span className="material-symbols-outlined">add</span>
|
||||
새 설비 등록
|
||||
|
||||
@@ -425,6 +425,23 @@ a {
|
||||
color: var(--md-on-surface-variant);
|
||||
}
|
||||
|
||||
.tenant-badge-dt {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-top: 4px;
|
||||
padding: 3px 10px;
|
||||
border-radius: 12px;
|
||||
background: var(--md-primary-container);
|
||||
color: var(--md-on-primary-container);
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.tenant-badge-dt .material-symbols-outlined {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* ===== Login ===== */
|
||||
.login-container {
|
||||
min-height: 100vh;
|
||||
|
||||
@@ -49,6 +49,12 @@ export default function HomePage() {
|
||||
<span className="material-symbols-outlined tenant-icon">factory</span>
|
||||
<span className="tenant-name">{tenant.name}</span>
|
||||
<span className="tenant-id">{tenant.id}</span>
|
||||
{tenant.has_digital_twin && (
|
||||
<span className="tenant-badge-dt">
|
||||
<span className="material-symbols-outlined">cloud</span>
|
||||
디지털 트윈 연동
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@ export interface Tenant {
|
||||
name: string;
|
||||
industry_type: string;
|
||||
is_active: boolean;
|
||||
has_digital_twin: boolean;
|
||||
created_at: string | null;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ async def get_tenant(db: AsyncSession, tenant_id: str) -> Dict:
|
||||
"name": str(tenant.name),
|
||||
"industry_type": str(tenant.industry_type),
|
||||
"is_active": bool(tenant.is_active),
|
||||
"has_digital_twin": bool(tenant.digital_twin_company_id),
|
||||
"created_at": _format_timestamp(tenant.created_at),
|
||||
}
|
||||
|
||||
@@ -99,6 +100,7 @@ async def list_tenants(db: AsyncSession) -> List[Dict]:
|
||||
"name": str(t.name),
|
||||
"industry_type": str(t.industry_type),
|
||||
"is_active": bool(t.is_active),
|
||||
"has_digital_twin": bool(t.digital_twin_company_id),
|
||||
"created_at": _format_timestamp(t.created_at),
|
||||
}
|
||||
for t in tenants
|
||||
|
||||
Reference in New Issue
Block a user