Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Commit ef2254d

Browse files
API 문서 필터링
1 parent c038d8e commit ef2254d

File tree

1 file changed

+58
-29
lines changed

1 file changed

+58
-29
lines changed

src/app/components/api-docs/api-docs.component.ts

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
99
import { MatFormFieldModule } from '@angular/material/form-field';
1010
import { MatInputModule } from '@angular/material/input';
1111
import { MatTooltipModule } from '@angular/material/tooltip';
12+
import { MatSelectModule } from '@angular/material/select';
1213
import { FormsModule } from '@angular/forms';
1314
import { AdminService, ApiDoc } from '../../services/admin.service';
1415

@@ -26,22 +27,37 @@ import { AdminService, ApiDoc } from '../../services/admin.service';
2627
MatFormFieldModule,
2728
MatInputModule,
2829
MatTooltipModule,
30+
MatSelectModule,
2931
FormsModule
3032
],
3133
template: `
3234
<div class="p-6 bg-md-sys-color-surface min-h-screen max-w-6xl mx-auto">
3335
<h1 class="md-typescale-headline-large text-md-sys-color-on-surface mb-6">API 문서</h1>
3436
3537
<div class="flex flex-col md:flex-row gap-4 mb-6">
36-
<div class="flex-1 max-w-md">
37-
<div class="relative">
38-
<input
39-
type="text"
40-
[(ngModel)]="searchTerm"
41-
(input)="filterApis()"
42-
placeholder="경로나 설명으로 검색..."
43-
class="w-full p-3 pr-12 bg-md-sys-color-surface-container-highest text-md-sys-color-on-surface rounded-xl border border-md-sys-color-outline focus:border-md-sys-color-primary focus:outline-none md-typescale-body-large">
44-
<mat-icon class="w-5 h-5 absolute right-3 top-1/2 transform -translate-y-1/2 text-md-sys-color-on-surface-variant">search</mat-icon>
38+
<div class="flex flex-col md:flex-row gap-4 flex-1">
39+
<div class="flex-1 max-w-md">
40+
<div class="relative">
41+
<input
42+
type="text"
43+
[(ngModel)]="searchTerm"
44+
(input)="filterApis()"
45+
placeholder="경로나 설명으로 검색..."
46+
class="w-full p-3 pr-12 bg-md-sys-color-surface-container-highest text-md-sys-color-on-surface rounded-xl border border-md-sys-color-outline focus:border-md-sys-color-primary focus:outline-none md-typescale-body-large">
47+
<mat-icon class="w-5 h-5 absolute right-3 top-1/2 transform -translate-y-1/2 text-md-sys-color-on-surface-variant">search</mat-icon>
48+
</div>
49+
</div>
50+
51+
<div class="w-full md:w-48">
52+
<mat-form-field appearance="outline" class="w-full">
53+
<mat-label>파일 필터</mat-label>
54+
<mat-select [(value)]="selectedFile" (selectionChange)="filterApis()">
55+
<mat-option value="">모든 파일</mat-option>
56+
<mat-option *ngFor="let file of getUniqueFiles()" [value]="file">
57+
{{ file }}
58+
</mat-option>
59+
</mat-select>
60+
</mat-form-field>
4561
</div>
4662
</div>
4763
@@ -101,7 +117,7 @@ import { AdminService, ApiDoc } from '../../services/admin.service';
101117
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 p-4 bg-md-sys-color-surface-container-high rounded-xl">
102118
<div class="flex items-center gap-2">
103119
<span class="md-typescale-body-medium font-medium text-md-sys-color-on-surface-variant">파일:</span>
104-
<span class="font-mono md-typescale-body-medium text-md-sys-color-on-surface">{{ doc.file }}.mjs</span>
120+
<span class="font-mono md-typescale-body-medium text-md-sys-color-on-surface">{{ doc.file }}</span>
105121
</div>
106122
<div class="flex items-center gap-2">
107123
<span class="md-typescale-body-medium font-medium text-md-sys-color-on-surface-variant">메소드:</span>
@@ -128,7 +144,7 @@ import { AdminService, ApiDoc } from '../../services/admin.service';
128144
<div *ngFor="let routeParam of doc.routeParams" class="p-3 bg-md-sys-color-primary-container rounded-lg">
129145
<div class="flex items-start justify-between mb-2">
130146
<div class="flex items-center gap-2">
131-
<code class="px-2 py-1 bg-md-sys-color-surface-container rounded text-sm font-mono text-md-sys-color-on-surface">:{{ routeParam.name }}</code>
147+
<code class="px-2 py-1 bg-md-sys-color-surface-container rounded text-sm font-mono text-md-sys-color-on-surface">{{ routeParam.name }}</code>
132148
<span class="px-2 py-1 rounded-full text-xs bg-md-sys-color-error-container text-md-sys-color-on-error-container">필수</span>
133149
</div>
134150
<span class="text-sm font-mono text-md-sys-color-on-primary-container">{{ routeParam.type }}</span>
@@ -226,6 +242,7 @@ export class ApiDocsComponent implements OnInit {
226242
apiDocs: ApiDoc[] = [];
227243
filteredDocs: ApiDoc[] = [];
228244
searchTerm = '';
245+
selectedFile = '';
229246
loading = false;
230247

231248
constructor(private adminService: AdminService) {}
@@ -234,6 +251,11 @@ export class ApiDocsComponent implements OnInit {
234251
this.loadApiDocs();
235252
}
236253

254+
getUniqueFiles(): string[] {
255+
const files = [...new Set(this.apiDocs.map(doc => doc.file))];
256+
return files.sort();
257+
}
258+
237259

238260
loadApiDocs() {
239261
this.loading = true;
@@ -258,26 +280,33 @@ export class ApiDocsComponent implements OnInit {
258280
}
259281

260282
filterApis() {
261-
if (!this.searchTerm.trim()) {
262-
this.filteredDocs = [...this.apiDocs];
263-
return;
283+
let filtered = [...this.apiDocs];
284+
285+
// File filter
286+
if (this.selectedFile) {
287+
filtered = filtered.filter(doc => doc.file === this.selectedFile);
288+
}
289+
290+
// Search term filter
291+
if (this.searchTerm.trim()) {
292+
const term = this.searchTerm.toLowerCase();
293+
filtered = filtered.filter(doc =>
294+
doc.path.toLowerCase().includes(term) ||
295+
doc.name.toLowerCase().includes(term) ||
296+
doc.method.toLowerCase().includes(term) ||
297+
doc.file.toLowerCase().includes(term) ||
298+
(doc.params && doc.params.some(param =>
299+
param.name.toLowerCase().includes(term) ||
300+
param.description.toLowerCase().includes(term)
301+
)) ||
302+
(doc.routeParams && doc.routeParams.some(routeParam =>
303+
routeParam.name.toLowerCase().includes(term) ||
304+
routeParam.description.toLowerCase().includes(term)
305+
))
306+
);
264307
}
265308

266-
const term = this.searchTerm.toLowerCase();
267-
this.filteredDocs = this.apiDocs.filter(doc =>
268-
doc.path.toLowerCase().includes(term) ||
269-
doc.name.toLowerCase().includes(term) ||
270-
doc.method.toLowerCase().includes(term) ||
271-
doc.file.toLowerCase().includes(term) ||
272-
(doc.params && doc.params.some(param =>
273-
param.name.toLowerCase().includes(term) ||
274-
param.description.toLowerCase().includes(term)
275-
)) ||
276-
(doc.routeParams && doc.routeParams.some(routeParam =>
277-
routeParam.name.toLowerCase().includes(term) ||
278-
routeParam.description.toLowerCase().includes(term)
279-
))
280-
);
309+
this.filteredDocs = filtered;
281310
}
282311

283312
refreshDocs() {

0 commit comments

Comments
 (0)