feat: replace mapping text input with company dropdown selector
All checks were successful
Deploy to Production / deploy (push) Successful in 1m11s

- Add proxy endpoint GET /api/admin/digital-twin/companies
- Fetch company list from digital-twin API on modal open
- Select dropdown shows company name + industry type
- Remove manual UUID input in favor of selection
This commit is contained in:
Johngreen
2026-02-12 15:18:52 +09:00
parent bcbffc9ce9
commit 9f4583229a
3 changed files with 85 additions and 22 deletions

View File

@@ -480,6 +480,19 @@ a {
padding: 0 24px;
}
.loading-inline {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 0;
font-size: 13px;
color: var(--md-on-surface-variant);
}
.loading-inline .material-symbols-outlined {
font-size: 18px;
}
/* ===== Login ===== */
.login-container {
min-height: 100vh;

View File

@@ -1,12 +1,18 @@
'use client';
import { useState } from 'react';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useAuth } from '@/lib/auth-context';
import { useTenants } from '@/lib/hooks';
import { Card } from '@/components/Card';
import { api } from '@/lib/api';
import { Tenant } from '@/lib/types';
import type { Tenant } from '@/lib/types';
interface DigitalTwinCompany {
companyId: string;
name: string;
industryType: string;
}
export default function HomePage() {
const { user, logout } = useAuth();
@@ -25,6 +31,17 @@ export default function HomePage() {
companyId: '',
});
const [isSaving, setIsSaving] = useState(false);
const [dtCompanies, setDtCompanies] = useState<DigitalTwinCompany[]>([]);
const [companiesLoading, setCompaniesLoading] = useState(false);
useEffect(() => {
if (!mappingModal.open) return;
setCompaniesLoading(true);
api.get<{ companies: DigitalTwinCompany[] }>('/api/admin/digital-twin/companies')
.then((res) => setDtCompanies(res.companies))
.catch(() => setDtCompanies([]))
.finally(() => setCompaniesLoading(false));
}, [mappingModal.open]);
const handleTenantSelect = (tenantId: string) => {
router.push(`/${tenantId}`);
@@ -136,30 +153,30 @@ export default function HomePage() {
<div className="modal-body-form">
<div className="form-field">
<label> ID</label>
<input
type="text"
value={mappingModal.companyId}
onChange={(e) => setMappingModal((prev) => ({ ...prev, companyId: e.target.value }))}
placeholder="회사 UUID (예: 7f5c058c-...)"
autoFocus
/>
<label> </label>
{companiesLoading ? (
<div className="loading-inline">
<span className="material-symbols-outlined spinning">progress_activity</span>
...
</div>
) : (
<select
value={mappingModal.companyId}
onChange={(e) => setMappingModal((prev) => ({ ...prev, companyId: e.target.value }))}
autoFocus
>
<option value=""> </option>
{dtCompanies.map((c) => (
<option key={c.companyId} value={c.companyId}>
{c.name} ({c.industryType})
</option>
))}
</select>
)}
</div>
</div>
<div className="modal-actions">
{mappingModal.companyId && (
<button
className="btn-outline btn-danger"
onClick={() => {
setMappingModal((prev) => ({ ...prev, companyId: '' }));
}}
disabled={isSaving}
style={{ marginRight: 'auto' }}
>
</button>
)}
<button
className="btn-text"
onClick={() => setMappingModal((prev) => ({ ...prev, open: false }))}

33
main.py
View File

@@ -155,6 +155,39 @@ async def update_tenant_digital_twin_mapping(
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/admin/digital-twin/companies")
async def list_digital_twin_companies(
current_user: TokenData = Depends(require_superadmin),
):
import httpx
api_url = os.getenv("DIGITAL_TWIN_API_URL", "")
if not api_url:
raise HTTPException(
status_code=503, detail="DIGITAL_TWIN_API_URL not configured"
)
try:
async with httpx.AsyncClient(timeout=10.0) as client:
resp = await client.get(f"{api_url}/api/v1/companies")
resp.raise_for_status()
data = resp.json()
companies = data.get("data", [])
return {
"companies": [
{
"companyId": c.get("companyId"),
"name": c.get("name"),
"industryType": c.get("industryType"),
}
for c in companies
]
}
except httpx.HTTPError as e:
raise HTTPException(
status_code=502, detail=f"Failed to fetch from digital-twin: {e}"
)
if __name__ == "__main__":
import uvicorn