release: 2026-03-31 (40건 커밋) #118

병합
HYOJIN develop 에서 main 로 40 commits 를 머지했습니다 2026-03-31 11:09:31 +09:00
9개의 변경된 파일59개의 추가작업 그리고 13개의 파일을 삭제
Showing only changes of commit e6e58bfc25 - Show all commits

파일 보기

@ -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();
}
}