release: 2026-03-31 (40건 커밋) #118
@ -14,6 +14,7 @@ export interface BypassParamDto {
|
||||
paramIn: string; // PATH, QUERY, BODY
|
||||
required: boolean;
|
||||
description: string;
|
||||
example: string; // Swagger @Parameter example 값
|
||||
sortOrder: number;
|
||||
}
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ export default function BypassStepBasic({
|
||||
<option value="">선택하세요</option>
|
||||
{webclientBeans.map((bean) => (
|
||||
<option key={bean.name} value={bean.name}>
|
||||
{bean.name}{bean.description ? ` — ${bean.description}` : ''}
|
||||
{bean.description || bean.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
@ -15,6 +15,7 @@ function createEmptyParam(sortOrder: number): BypassParamDto {
|
||||
paramIn: 'QUERY',
|
||||
required: false,
|
||||
description: '',
|
||||
example: '',
|
||||
sortOrder,
|
||||
};
|
||||
}
|
||||
@ -58,6 +59,7 @@ export default function BypassStepParams({ params, onChange }: BypassStepParamsP
|
||||
<th className="pb-2 text-left font-medium text-wing-muted pr-3 min-w-[100px]">위치</th>
|
||||
<th className="pb-2 text-center font-medium text-wing-muted pr-3 w-14">필수</th>
|
||||
<th className="pb-2 text-left font-medium text-wing-muted pr-3">설명</th>
|
||||
<th className="pb-2 text-left font-medium text-wing-muted pr-3 min-w-[120px]">Example</th>
|
||||
<th className="pb-2 w-10"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -112,6 +114,15 @@ export default function BypassStepParams({ params, onChange }: BypassStepParamsP
|
||||
className="w-full px-2 py-1.5 text-sm rounded border border-wing-border bg-wing-surface text-wing-text placeholder:text-wing-muted focus:outline-none focus:ring-1 focus:ring-wing-accent/50"
|
||||
/>
|
||||
</td>
|
||||
<td className="py-2 pr-3">
|
||||
<input
|
||||
type="text"
|
||||
value={param.example}
|
||||
onChange={(e) => handleChange(index, 'example', e.target.value)}
|
||||
placeholder="예: 9876543"
|
||||
className="w-full px-2 py-1.5 text-sm rounded border border-wing-border bg-wing-surface text-wing-text placeholder:text-wing-muted focus:outline-none focus:ring-1 focus:ring-wing-accent/50"
|
||||
/>
|
||||
</td>
|
||||
<td className="py-2">
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@ -32,8 +32,9 @@ export default function BypassConfig() {
|
||||
const [configs, setConfigs] = useState<BypassConfigResponse[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [webclientBeans, setWebclientBeans] = useState<WebClientBeanInfo[]>([]);
|
||||
const [viewMode, setViewMode] = useState<ViewMode>('card');
|
||||
const [viewMode, setViewMode] = useState<ViewMode>('table');
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [selectedDomain, setSelectedDomain] = useState('');
|
||||
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [editConfig, setEditConfig] = useState<BypassConfigResponse | null>(null);
|
||||
@ -110,15 +111,21 @@ export default function BypassConfig() {
|
||||
}
|
||||
};
|
||||
|
||||
const domainNames = useMemo(() => {
|
||||
const names = [...new Set(configs.map((c) => c.domainName))];
|
||||
return names.sort();
|
||||
}, [configs]);
|
||||
|
||||
const filteredConfigs = useMemo(() => {
|
||||
if (!searchTerm.trim()) return configs;
|
||||
const term = searchTerm.toLowerCase();
|
||||
return configs.filter(
|
||||
(c) =>
|
||||
c.domainName.toLowerCase().includes(term) ||
|
||||
c.displayName.toLowerCase().includes(term),
|
||||
);
|
||||
}, [configs, searchTerm]);
|
||||
return configs.filter((c) => {
|
||||
const matchesSearch =
|
||||
!searchTerm.trim() ||
|
||||
c.domainName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
c.displayName.toLowerCase().includes(searchTerm.toLowerCase());
|
||||
const matchesDomain = !selectedDomain || c.domainName === selectedDomain;
|
||||
return matchesSearch && matchesDomain;
|
||||
});
|
||||
}, [configs, searchTerm, selectedDomain]);
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
|
||||
@ -177,6 +184,18 @@ export default function BypassConfig() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 도메인 드롭다운 필터 */}
|
||||
<select
|
||||
value={selectedDomain}
|
||||
onChange={(e) => setSelectedDomain(e.target.value)}
|
||||
className="px-3 py-2 text-sm rounded-lg border border-wing-border bg-wing-surface text-wing-text"
|
||||
>
|
||||
<option value="">전체 도메인</option>
|
||||
{domainNames.map((name) => (
|
||||
<option key={name} value={name}>{name}</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
{/* 뷰 전환 토글 */}
|
||||
<div className="flex rounded-lg border border-wing-border overflow-hidden">
|
||||
<button
|
||||
@ -215,7 +234,7 @@ export default function BypassConfig() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{searchTerm && (
|
||||
{(searchTerm || selectedDomain) && (
|
||||
<p className="mt-2 text-xs text-wing-muted">
|
||||
{filteredConfigs.length}개 API 검색됨
|
||||
</p>
|
||||
|
||||
@ -15,8 +15,10 @@ public class WebViewController {
|
||||
@GetMapping({"/", "/jobs", "/executions", "/executions/{id:\\d+}",
|
||||
"/recollects", "/recollects/{id:\\d+}",
|
||||
"/schedules", "/schedule-timeline", "/monitoring",
|
||||
"/bypass-config",
|
||||
"/jobs/**", "/executions/**", "/recollects/**",
|
||||
"/schedules/**", "/schedule-timeline/**", "/monitoring/**"})
|
||||
"/schedules/**", "/schedule-timeline/**", "/monitoring/**",
|
||||
"/bypass-config/**"})
|
||||
public String forward() {
|
||||
return "forward:/index.html";
|
||||
}
|
||||
|
||||
@ -33,4 +33,7 @@ public class BypassParamDto {
|
||||
|
||||
/** 정렬 순서 */
|
||||
private Integer sortOrder;
|
||||
|
||||
/** Swagger @Parameter example 값 */
|
||||
private String example;
|
||||
}
|
||||
|
||||
@ -74,4 +74,10 @@ public class BypassApiParam {
|
||||
@Column(name = "sort_order", nullable = false)
|
||||
@Builder.Default
|
||||
private Integer sortOrder = 0;
|
||||
|
||||
/**
|
||||
* Swagger @Parameter example 값
|
||||
*/
|
||||
@Column(name = "example", length = 200)
|
||||
private String example;
|
||||
}
|
||||
|
||||
@ -283,7 +283,9 @@ public class BypassCodeGenerator {
|
||||
String description = p.getDescription() != null ? p.getDescription() : p.getParamName();
|
||||
String javaType = toJavaType(p.getParamType());
|
||||
String paramName = p.getParamName();
|
||||
String example = getDefaultExample(p.getParamType());
|
||||
String example = (p.getExample() != null && !p.getExample().isEmpty())
|
||||
? p.getExample()
|
||||
: getDefaultExample(p.getParamType());
|
||||
return switch (p.getParamIn().toUpperCase()) {
|
||||
case "PATH" -> "@Parameter(description = \"" + description + "\", example = \"" + example + "\")\n"
|
||||
+ " @PathVariable " + javaType + " " + paramName;
|
||||
|
||||
@ -170,6 +170,7 @@ public class BypassConfigService {
|
||||
.required(dto.getRequired() != null ? dto.getRequired() : true)
|
||||
.description(dto.getDescription())
|
||||
.sortOrder(dto.getSortOrder() != null ? dto.getSortOrder() : 0)
|
||||
.example(dto.getExample())
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -182,6 +183,7 @@ public class BypassConfigService {
|
||||
.required(param.getRequired())
|
||||
.description(param.getDescription())
|
||||
.sortOrder(param.getSortOrder())
|
||||
.example(param.getExample())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user