Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions apps/desktop/Sources/SkimDesktopApp/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ struct ContentView: View {
Button {
showManager = true
} label: {
Label("소스/크레덴셜 관리", systemImage: "gearshape")
Label("유튜브 채널/크레덴셜 관리", systemImage: "gearshape")
}
}
}
Expand Down Expand Up @@ -455,7 +455,7 @@ struct ContentView: View {
VStack(spacing: 0) {
HStack {
Picker("", selection: $managerTab) {
Text("소스").tag(ManagerTab.sources)
Text("유튜브 채널").tag(ManagerTab.sources)
Text("크레덴셜").tag(ManagerTab.credentials)
}
.pickerStyle(.segmented)
Expand Down Expand Up @@ -513,9 +513,9 @@ struct ContentView: View {
}

VStack(alignment: .leading, spacing: 10) {
sectionLabel("추적 중인 소스 \(snapshot.sources.count.formatted())개")
sectionLabel("추적 중인 유튜브 채널 \(snapshot.sources.count.formatted())개")
if snapshot.sources.isEmpty {
emptyLine("추적 중인 소스 없음")
emptyLine("추적 중인 유튜브 채널 없음")
} else {
ScrollView {
LazyVStack(spacing: 6) {
Expand Down Expand Up @@ -694,6 +694,12 @@ struct ContentView: View {
.padding(.horizontal, 10)
.padding(.vertical, 8)
.background(Design.panelBackground.opacity(0.72), in: RoundedRectangle(cornerRadius: 8))
.contentShape(Rectangle())
.onTapGesture {
if let url = URL(string: source.handleOrURL ?? "") {
NSWorkspace.shared.open(url)
}
}
Comment on lines +698 to +702

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

유튜브 채널의 handleOrURL은 옵셔널 값이며, 데이터베이스 상태에 따라 비어있거나 올바르지 않은 URL 스키마(예: file:// 등 안전하지 않은 스키마)를 가질 가능성이 있습니다. 안전한 이동을 위해 값이 비어있지 않은지 확인하고, URL 스키마가 http 또는 https인지 검증한 후 NSWorkspace.shared.open을 호출하는 것이 안전합니다.\n\n또한, 현재 sourceRow 전체에 .onTapGesture가 적용되어 있어, 행 내부의 삭제(trash) 버튼을 클릭할 때 삭제 얼럿이 뜨는 동시에 유튜브 채널 페이지가 브라우저에서 열리는 부작용(이벤트 전파)이 발생할 수 있습니다. 이를 방지하기 위해, 추후 리팩토링 시 텍스트 영역(이름, 플랫폼 정보 등)만 별도의 HStack이나 VStack으로 감싸고 해당 영역에만 .onTapGesture를 적용하고, 삭제 버튼은 그 바깥에 배치하는 구조로 개선하는 것을 권장합니다.

Suggested change
.onTapGesture {
if let url = URL(string: source.handleOrURL ?? "") {
NSWorkspace.shared.open(url)
}
}
.onTapGesture {
if let handleOrURL = source.handleOrURL,
!handleOrURL.isEmpty,
let url = URL(string: handleOrURL),
url.scheme == "http" || url.scheme == "https" {
NSWorkspace.shared.open(url)
}
}

}

private func credentialRow(_ credential: PlatformCredential) -> some View {
Expand Down
7 changes: 7 additions & 0 deletions prompts/2026-07-04.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"time": "22:12:45",
"user": "seungwonan",
"prompt": "그냥 메인에 해줘 워크트리 정리하고"
}
]
Comment on lines +1 to +7

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

이 파일은 개발 과정에서 사용된 프롬프트 기록이나 임시 로그 파일로 보입니다. 실제 애플리케이션 실행이나 빌드에 필요하지 않은 파일이므로, 실수로 커밋된 것이라면 PR에서 제외하고 삭제하는 것이 좋습니다.

Loading