From 4216d42d7c8e845cd5906e3644545120023d18d5 Mon Sep 17 00:00:00 2001
From: th-kim0823
Date: Mon, 11 May 2026 16:25:38 +0900
Subject: [PATCH] =?UTF-8?q?chore(release):=20v0.3.7=20=E2=80=94=20?=
=?UTF-8?q?=EC=9D=B4=EB=8F=99=20modal=20currentStatus=20=ED=95=84=ED=84=B0?=
=?UTF-8?q?=20(Inbox=20=EB=B3=B5=EC=9B=90=20path)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
MoveStatusModal 이 완료/보관/휴지통 3 button hardcode 라
완료/보관/휴지통 노트가 inbox 로 돌아오는 path 가 없던 버그 fix.
currentStatus prop 으로 4 status 중 current 제외 동적 render.
'활성' label 도 헤더 탭과 일치하도록 'Inbox' 로 통일.
Co-Authored-By: Claude Opus 4.7 (1M context)
---
CHANGELOG.md | 19 +++++++
package-lock.json | 4 +-
package.json | 2 +-
.../inbox/components/MoveStatusModal.tsx | 22 +++++--
src/renderer/inbox/components/NoteCard.tsx | 1 +
tests/unit/MoveStatusModal.test.tsx | 57 +++++++++++++++++++
6 files changed, 96 insertions(+), 9 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c8b14a3..9ff42df 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,25 @@
본 파일은 Inkling 의 버전별 사용자 영향 변경 사항을 기록한다.
형식은 [Keep a Changelog](https://keepachangelog.com/) 를 느슨하게 따른다.
+## [0.3.7] — 2026-05-11
+
+`MoveStatusModal` 의 button hardcode 로 인해 완료/보관/휴지통 노트가 inbox 로 돌아올 수 없던 버그 fix. v0.2.9 Cut B 부터 존재한 잠재 결함 (dropdown 의 `possibleTargets` 필터가 modal 까지 흐르지 못함).
+
+### 수정
+
+- **완료/보관/휴지통 노트의 Inbox 복원 path 부재.** `MoveStatusModal` 이 `완료/보관/휴지통` 3 button hardcode 라 currentStatus 외 3 status 만 동적으로 노출해야 한다는 의도가 누락. `currentStatus: NoteStatus` prop 추가 + 4 status 중 current 제외 동적 render. NoteCard 가 `local.status` 전달.
+- **status label 일관성** — `statusLabel('active')` 가 '활성' 이었으나 헤더 탭 표기는 'Inbox'. modal button + AI 추천 텍스트 양쪽 모두 'Inbox' 로 통일.
+
+### 게이트
+
+- 단위 736 → **739 PASS** (+3: completed/archived/trashed currentStatus button list 검증)
+- typecheck 0 errors (src)
+- 신규 npm dependency 0
+
+### 업그레이드
+
+v0.3.6 인스톨러 위에 v0.3.7 인스톨러를 같은 위치에 실행하면 in-place 업그레이드. 데이터/마이그레이션 변경 없음.
+
## [0.3.6] — 2026-05-11
v0.3.5 의 이동 dropdown 단순화가 사용자 의도와 어긋난 점 정정. 이동 modal (사유 + AI 자동 분류 + 수동 status 선택) 은 보존해야 하는 핵심 UX 였음.
diff --git a/package-lock.json b/package-lock.json
index 554489f..e70f49e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "inkling",
- "version": "0.3.6",
+ "version": "0.3.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "inkling",
- "version": "0.3.6",
+ "version": "0.3.7",
"dependencies": {
"better-sqlite3": "12.9.0",
"electron-log": "5.2.0",
diff --git a/package.json b/package.json
index 8aecc98..f8b6882 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "inkling",
- "version": "0.3.6",
+ "version": "0.3.7",
"private": true,
"description": "Inkling — local-first 한 줄 보관 도구",
"author": "altair823 ",
diff --git a/src/renderer/inbox/components/MoveStatusModal.tsx b/src/renderer/inbox/components/MoveStatusModal.tsx
index 814f0b7..fa8bac1 100644
--- a/src/renderer/inbox/components/MoveStatusModal.tsx
+++ b/src/renderer/inbox/components/MoveStatusModal.tsx
@@ -6,17 +6,24 @@ interface Props {
noteId: string;
rawText: string;
summary: string;
+ /** 현재 노트 status. 이 값을 제외한 나머지 status 가 이동 버튼으로 노출. */
+ currentStatus: NoteStatus;
onClose: () => void;
onMoved: (status: NoteStatus, reason: string | null) => void;
}
/**
- * v0.2.9 Cut B Task 7 — 메모 이동 Modal.
+ * 메모 이동 Modal.
*
- * 사유 입력 + 3 status 버튼 (완료/보관/휴지통) + AI 자동 분류.
+ * 사유 입력 + AI 자동 분류 + 수동 status 선택. 버튼은 currentStatus 를 제외한
+ * 나머지 status 만 노출 (v0.3.6 까지는 완료/보관/휴지통 hardcode 라 완료/보관 노트가
+ * inbox 로 못 돌아오던 버그를 v0.3.7 에서 정정).
*/
+const ALL_STATUSES: readonly NoteStatus[] = ['active', 'completed', 'archived', 'trashed'];
+
export function MoveStatusModal({
noteId,
+ currentStatus,
onClose,
onMoved
}: Props): React.ReactElement {
@@ -90,9 +97,11 @@ export function MoveStatusModal({
-
-
-
+ {ALL_STATUSES.filter((s) => s !== currentStatus).map((s) => (
+
+ ))}
@@ -126,7 +135,8 @@ export function MoveStatusModal({
export function statusLabel(s: NoteStatus): string {
switch (s) {
case 'active':
- return '활성';
+ // 헤더 탭 표기 ('Inbox') 와 일치. UI 전반에서 active = Inbox 동의어.
+ return 'Inbox';
case 'completed':
return '완료';
case 'archived':
diff --git a/src/renderer/inbox/components/NoteCard.tsx b/src/renderer/inbox/components/NoteCard.tsx
index 11f6612..ef6280b 100644
--- a/src/renderer/inbox/components/NoteCard.tsx
+++ b/src/renderer/inbox/components/NoteCard.tsx
@@ -468,6 +468,7 @@ export function NoteCard({ note, onDeleted, onUpdated, mode = 'inbox', onRestore
noteId={local.id}
rawText={local.rawText}
summary={local.aiSummary ?? ''}
+ currentStatus={local.status}
onClose={() => setMoveOpen(false)}
onMoved={(newStatus, reason) => {
const updated = { ...local, status: newStatus, moveReason: reason };
diff --git a/tests/unit/MoveStatusModal.test.tsx b/tests/unit/MoveStatusModal.test.tsx
index c083a86..7e41104 100644
--- a/tests/unit/MoveStatusModal.test.tsx
+++ b/tests/unit/MoveStatusModal.test.tsx
@@ -32,6 +32,7 @@ describe('MoveStatusModal', () => {
noteId="n1"
rawText="t"
summary=""
+ currentStatus="active"
onClose={vi.fn()}
onMoved={vi.fn()}
/>
@@ -50,6 +51,7 @@ describe('MoveStatusModal', () => {
noteId="n1"
rawText="t"
summary=""
+ currentStatus="active"
onClose={vi.fn()}
onMoved={onMoved}
/>
@@ -69,6 +71,7 @@ describe('MoveStatusModal', () => {
noteId="n1"
rawText="t"
summary=""
+ currentStatus="active"
onClose={vi.fn()}
onMoved={onMoved}
/>
@@ -81,6 +84,59 @@ describe('MoveStatusModal', () => {
await waitFor(() => expect(onMoved).toHaveBeenCalledWith('completed', '결재 끝'));
});
+ it('currentStatus=completed → Inbox/보관/휴지통 노출, 완료 미노출', () => {
+ render(
+
+ );
+ expect(screen.getByRole('button', { name: 'Inbox' })).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: '보관' })).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: '휴지통' })).toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: '완료' })).toBeNull();
+ });
+
+ it('currentStatus=archived → Inbox 버튼 클릭 시 setStatus("active") 호출', async () => {
+ const onMoved = vi.fn();
+ render(
+
+ );
+ fireEvent.click(screen.getByRole('button', { name: 'Inbox' }));
+ await waitFor(() => {
+ expect(mockSetStatus).toHaveBeenCalledWith('n1', 'active', null);
+ expect(onMoved).toHaveBeenCalledWith('active', null);
+ });
+ });
+
+ it('currentStatus=trashed → Inbox/완료/보관 노출, 휴지통 미노출', () => {
+ render(
+
+ );
+ expect(screen.getByRole('button', { name: 'Inbox' })).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: '완료' })).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: '보관' })).toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: '휴지통' })).toBeNull();
+ });
+
it('빈 사유 → null reason 전달', async () => {
const onMoved = vi.fn();
render(
@@ -88,6 +144,7 @@ describe('MoveStatusModal', () => {
noteId="n1"
rawText="t"
summary=""
+ currentStatus="active"
onClose={vi.fn()}
onMoved={onMoved}
/>