Skip to content

Commit 5e9a8f0

Browse files
committed
can modify name of notes
1 parent 75eb4ee commit 5e9a8f0

7 files changed

Lines changed: 208 additions & 9 deletions

File tree

.env.example

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,7 @@ LANGCHAIN_PROJECT=open-notebook
7474
ALLOW_DELETE=true
7575

7676
# 允许为一个笔记本创建多个相同类型的笔记(默认为 true)
77-
ALLOW_MULTIPLE_NOTES_OF_SAME_TYPE=true
77+
ALLOW_MULTIPLE_NOTES_OF_SAME_TYPE=true
78+
79+
# 允许修改笔记本名称(默认为 true)
80+
ALLOW_NOTEBOOK_RENAME=true

backend/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type Config struct {
5151
// Demo settings
5252
AllowDelete bool
5353
AllowMultipleNotesOfSameType bool
54+
AllowNotebookRename bool
5455

5556
// LangSmith tracing (optional)
5657
LangChainAPIKey string
@@ -98,6 +99,7 @@ func LoadConfig() Config {
9899
EnableMarkitdown: getEnvBool("ENABLE_MARKITDOWN", true),
99100
AllowDelete: getEnvBool("ALLOW_DELETE", true),
100101
AllowMultipleNotesOfSameType: getEnvBool("ALLOW_MULTIPLE_NOTES_OF_SAME_TYPE", true),
102+
AllowNotebookRename: getEnvBool("ALLOW_NOTEBOOK_RENAME", true),
101103
LangChainAPIKey: getEnv("LANGCHAIN_API_KEY", ""),
102104
LangChainProject: getEnv("LANGCHAIN_PROJECT", "open-notebook"),
103105
}

backend/frontend/index.html

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,24 @@ <h1>我的笔记本</h1>
6868
</svg>
6969
返回列表
7070
</button>
71-
<div class="current-notebook-info">
72-
<h2 id="currentNotebookName">笔记本名称</h2>
71+
<div class="current-notebook-info" id="notebookNameContainer">
72+
<h2 id="currentNotebookName" class="notebook-name-display">笔记本名称</h2>
73+
<div id="notebookNameEditor" class="notebook-name-editor hidden">
74+
<input type="text" id="notebookNameInput" class="notebook-name-input" maxlength="50" />
75+
<div class="notebook-name-actions">
76+
<button id="btnSaveNotebookName" class="btn-icon btn-save" title="保存">
77+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2">
78+
<polyline points="13,4 6,11 3,8"/>
79+
</svg>
80+
</button>
81+
<button id="btnCancelNotebookName" class="btn-icon btn-cancel" title="取消">
82+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2">
83+
<line x1="4" y1="4" x2="12" y2="12"/>
84+
<line x1="12" y1="4" x2="4" y2="12"/>
85+
</svg>
86+
</button>
87+
</div>
88+
</div>
7389
</div>
7490
<div class="workspace-actions">
7591
<a href="https://github.com/smallnest/notex" target="_blank" class="btn-github" title="GitHub 仓库" style="margin-right: 8px;">

backend/frontend/static/app.js

Lines changed: 119 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ class OpenNotebook {
157157
await this.loadConfig();
158158
this.bindEvents();
159159
this.initResizers();
160+
this.initNotebookNameEditor();
160161
this.switchView('landing');
161162

162163
// 清理过期缓存
@@ -171,7 +172,8 @@ class OpenNotebook {
171172
const config = await this.api('/config');
172173
// Convert snake_case to camelCase
173174
this.config = {
174-
allowDelete: config.allow_delete !== undefined ? config.allow_delete : true
175+
allowDelete: config.allow_delete !== undefined ? config.allow_delete : true,
176+
allowNotebookRename: config.allow_notebook_rename !== undefined ? config.allow_notebook_rename : true
175177
};
176178
} catch (error) {
177179
console.error('Failed to load config:', error);
@@ -621,10 +623,19 @@ class OpenNotebook {
621623

622624
async selectNotebook(id) {
623625
this.currentNotebook = this.notebooks.find(nb => nb.id === id);
624-
625-
document.getElementById('currentNotebookName').textContent = this.currentNotebook.name;
626+
627+
const nameDisplay = document.getElementById('currentNotebookName');
628+
nameDisplay.textContent = this.currentNotebook.name;
629+
630+
// 设置可编辑状态
631+
if (this.config.allowNotebookRename) {
632+
nameDisplay.classList.add('editable');
633+
} else {
634+
nameDisplay.classList.remove('editable');
635+
}
636+
626637
this.switchView('workspace');
627-
638+
628639
// Reset tab to notes list and remove any existing note view
629640
this.showNotesListTab();
630641
const noteView = document.querySelector('.note-view-container');
@@ -639,6 +650,110 @@ class OpenNotebook {
639650
this.setStatus(`当前选择: ${this.currentNotebook.name}`);
640651
}
641652

653+
initNotebookNameEditor() {
654+
const nameDisplay = document.getElementById('currentNotebookName');
655+
const nameEditor = document.getElementById('notebookNameEditor');
656+
const nameInput = document.getElementById('notebookNameInput');
657+
const saveBtn = document.getElementById('btnSaveNotebookName');
658+
const cancelBtn = document.getElementById('btnCancelNotebookName');
659+
660+
// 双击进入编辑模式
661+
nameDisplay.addEventListener('dblclick', () => {
662+
if (!this.config.allowNotebookRename) return;
663+
this.startEditingNotebookName();
664+
});
665+
666+
// 点击保存按钮
667+
saveBtn.addEventListener('click', () => {
668+
this.saveNotebookName();
669+
});
670+
671+
// 点击取消按钮
672+
cancelBtn.addEventListener('click', () => {
673+
this.cancelEditNotebookName();
674+
});
675+
676+
// 输入框回车保存
677+
nameInput.addEventListener('keydown', (e) => {
678+
if (e.key === 'Enter') {
679+
this.saveNotebookName();
680+
} else if (e.key === 'Escape') {
681+
this.cancelEditNotebookName();
682+
}
683+
});
684+
}
685+
686+
startEditingNotebookName() {
687+
const nameDisplay = document.getElementById('currentNotebookName');
688+
const nameEditor = document.getElementById('notebookNameEditor');
689+
const nameInput = document.getElementById('notebookNameInput');
690+
691+
nameInput.value = this.currentNotebook.name;
692+
nameDisplay.classList.add('hidden');
693+
nameEditor.classList.remove('hidden');
694+
nameInput.focus();
695+
nameInput.select();
696+
}
697+
698+
async saveNotebookName() {
699+
const nameInput = document.getElementById('notebookNameInput');
700+
const newName = nameInput.value.trim();
701+
702+
if (!newName) {
703+
this.showError('笔记本名称不能为空');
704+
return;
705+
}
706+
707+
if (newName === this.currentNotebook.name) {
708+
this.cancelEditNotebookName();
709+
return;
710+
}
711+
712+
try {
713+
this.showLoading('保存中...');
714+
715+
const updated = await this.api(`/notebooks/${this.currentNotebook.id}`, {
716+
method: 'PUT',
717+
body: JSON.stringify({
718+
name: newName,
719+
description: this.currentNotebook.description
720+
})
721+
});
722+
723+
// 更新本地数据
724+
this.currentNotebook.name = newName;
725+
this.currentNotebook.updated_at = updated.updated_at;
726+
727+
// 更新 notebooks 列表中的数据
728+
const nb = this.notebooks.find(n => n.id === this.currentNotebook.id);
729+
if (nb) {
730+
nb.name = newName;
731+
nb.updated_at = updated.updated_at;
732+
}
733+
734+
// 使缓存失效
735+
this.cache.delete('notebooks');
736+
737+
// 更新显示
738+
document.getElementById('currentNotebookName').textContent = newName;
739+
this.cancelEditNotebookName();
740+
this.hideLoading();
741+
this.setStatus('笔记本名称已更新');
742+
743+
} catch (error) {
744+
this.hideLoading();
745+
this.showError(error.message);
746+
}
747+
}
748+
749+
cancelEditNotebookName() {
750+
const nameDisplay = document.getElementById('currentNotebookName');
751+
const nameEditor = document.getElementById('notebookNameEditor');
752+
753+
nameDisplay.classList.remove('hidden');
754+
nameEditor.classList.add('hidden');
755+
}
756+
642757
showNewNotebookModal() {
643758
document.getElementById('newNotebookModal').classList.add('active');
644759
document.getElementById('modalOverlay').classList.add('active');

backend/frontend/static/style.css

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2608,6 +2608,67 @@ body {
26082608
font-weight: 600;
26092609
}
26102610

2611+
.notebook-name-display {
2612+
cursor: default;
2613+
transition: all var(--transition-fast);
2614+
}
2615+
2616+
.notebook-name-display.editable {
2617+
cursor: pointer;
2618+
}
2619+
2620+
.notebook-name-display.editable:hover {
2621+
color: var(--accent-primary);
2622+
}
2623+
2624+
.notebook-name-editor {
2625+
display: flex;
2626+
align-items: center;
2627+
gap: var(--space-sm);
2628+
}
2629+
2630+
.notebook-name-editor.hidden {
2631+
display: none;
2632+
}
2633+
2634+
.notebook-name-input {
2635+
font-size: 1.1rem;
2636+
font-weight: 600;
2637+
padding: 4px 8px;
2638+
border: 1px solid var(--accent-primary);
2639+
border-radius: var(--radius-sm);
2640+
background: var(--bg-primary);
2641+
color: var(--text-primary);
2642+
outline: none;
2643+
min-width: 200px;
2644+
}
2645+
2646+
.notebook-name-input:focus {
2647+
box-shadow: 0 0 0 2px var(--accent-light);
2648+
}
2649+
2650+
.notebook-name-actions {
2651+
display: flex;
2652+
gap: var(--space-xs);
2653+
}
2654+
2655+
.notebook-name-actions .btn-save {
2656+
color: var(--accent-primary);
2657+
}
2658+
2659+
.notebook-name-actions .btn-save:hover {
2660+
background: var(--accent-light);
2661+
}
2662+
2663+
.notebook-name-actions .btn-cancel {
2664+
color: var(--text-secondary);
2665+
}
2666+
2667+
.notebook-name-actions .btn-cancel:hover {
2668+
background: var(--bg-hover);
2669+
color: var(--text-primary);
2670+
}
2671+
26112672
/* Note View Container */
26122673
.note-view-container {
26132674
display: none;

backend/server.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ func (s *Server) handleHealth(c *gin.Context) {
194194

195195
func (s *Server) handleConfig(c *gin.Context) {
196196
c.JSON(http.StatusOK, ConfigResponse{
197-
AllowDelete: s.cfg.AllowDelete,
197+
AllowDelete: s.cfg.AllowDelete,
198+
AllowNotebookRename: s.cfg.AllowNotebookRename,
198199
})
199200
}
200201

backend/types.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,5 +152,6 @@ type HealthResponse struct {
152152

153153
// ConfigResponse represents the client configuration
154154
type ConfigResponse struct {
155-
AllowDelete bool `json:"allow_delete"`
155+
AllowDelete bool `json:"allow_delete"`
156+
AllowNotebookRename bool `json:"allow_notebook_rename"`
156157
}

0 commit comments

Comments
 (0)