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
2 changes: 1 addition & 1 deletion docs/feature-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ sidebar, insets + rounds the content area, and re-homes the toolbar off-screen.
| ☐ | Native tab context-menu shortcut labels | `dao_sidebar_ui.cc` | 🟡 | Right-click a regular tab → Duplicate Tab shows ⌘D, Copy Link shows ⌘⇧C, and Close Tab shows ⌘W; each shortcut still performs the matching action |
| ☐ | Pinned sites/tabs grid, stable backing identity, and dormant pinned items | `src/dao/.../sidebar/dao_pinned_tabs_grid.ts`, `dao_pinned_tab_model.{h,cc}`, `dao_pinned_tab_storage.{h,cc}`, `dao_tab_identity.{h,cc}`, `dao_sidebar_ui.cc`, `sessions/session_service.cc.patch` | `DaoPinnedTabModelTest.*`, `DaoPinnedTabStorageTest.*`, `DaoSidebarBrowserTest.*Pinned*`, `DaoSidebarBrowserTest.ActivatingPinnedItemReusesTabFromAnotherWindow`, `DaoSidebarBrowserTest.ClosingPinnedItemFromAnotherWindowMakesItDormantAndReopenable`, `DaoSidebarBrowserTest.UnpinningPinnedItemFromAnotherWindowMovesItHere`, `DaoTabBrowserTest.SidebarTabIdentity*`, `pinned_tabs_grid.test.ts` | Pin and activate without changing tab count; navigate; discard/replace WebContents; replace then navigate; restore the session after command compaction and preserve the backing identity; activate the same Pin from another window and focus the existing tab without increasing either window's tab count; close it remotely and synchronize dormant state across windows; drag a remote Pin into the current ordinary tab list and move the backing tab into this window; block clicks and unpin drags until restore completes; close then reopen once; double-click; create two identical-URL tabs and preserve exact ownership; create a legacy identity conflict and verify active tab/tab count remain unchanged; reject partially invalid migration data without dropping Pins; verify failed atomic persistence preserves the previous file; drag/reorder does not corrupt state |
| ☐ | Active sidebar tab stays visible after tab switches | `dao_sidebar_app.ts`, `dao_tab_item.ts`, `dao_folder_item.ts`, sidebar WebUI tests | — | Scroll the tab list away from a visible tab, activate it by keyboard or another surface, and verify it smoothly enters the nearest viewport edge; activate a child of a collapsed folder and verify the folder expands, persists the expanded state, and scrolls the child into view |
| ☐ | Sidebar folder model + configurable stale-tab actions | `src/dao/.../sidebar/dao_folder_model.ts`, `dao_sidebar_app.ts`, `dao_sidebar_ui.cc`, Settings Dao page patches | `DaoSidebarBrowserTest.StaleTabExpirationPrefDefaultsTo24Hours`, `sidebar_app.test.ts`, `dao_page_test.ts` | "You and Dao" accepts only integer hours from 1–720 and defaults to 24; invalid input is not saved; "Move Stale Tabs to stale" reads the current profile value, creates/updates the `stale` folder only for qualifying ordinary tabs, expands it, and persists folder membership. Right-click `stale` → Clear Stale Tabs is present; ordinary folders omit it; the Dao native system confirmation dialog appears; Cancel preserves tabs/folder; Clear closes only current `stale` children and deletes the folder. |
| ☐ | Sidebar folder model, Unfolder/Delete Folder, and configurable stale-tab archiving | `src/dao/.../sidebar/dao_folder_model.ts`, `dao_sidebar_app.ts`, `dao_sidebar_ui.cc`, Settings Dao page patches | `DaoSidebarBrowserTest.StaleTabExpirationPrefDefaultsTo24Hours`, `DaoSidebarBrowserTest.DeleteFolderUsesDaoNativeDialog`, `sidebar_app.test.ts`, `folder_model.test.ts`, `dao_page_test.ts` | "You and Dao" accepts only integer hours from 1–720 and defaults to 24; invalid input is not saved; "Move Stale Tabs to stale" reads the current profile value, creates/updates the `stale` folder only for qualifying ordinary tabs, expands it, and persists folder membership. Every folder, including `stale`, exposes the same context menu: Unfolder removes the folder and releases children in place without closing tabs; Delete Folder opens the Dao native confirmation dialog. Cancel preserves tabs/folder; confirmation closes only current matched children and persists deletion only after all of them actually close; cancelling a page's beforeunload prompt keeps the folder and remaining tabs. Verify ordinary, stale, empty, missing, renamed, changed-membership, ordered-child, and cancelled-close cases. |
| ☐ | Sidebar utility controls: downloads, media controls, update button | `dao_download_button.ts`, `dao_download_hover_details.*`, `dao_tab_tooltip_view.*`, `dao_media_control.ts`, `dao_update_button.ts`, `dao_sidebar_ui.cc` | — | Active download rows retain progress/cancel behavior; a settled 400ms hover shows a native popup beyond the sidebar boundary with full filename, known transferred/total size and percentage, positive speed, and reliable remaining time. Long filenames wrap without truncation; hovering the lowest row flips the popup above its anchor and keeps all lines inside the browser window. Moving resets the delay; leaving, cancelling, or removing the download hides it. Unknown totals degrade to transferred size only; unavailable speed/time are omitted. Verify light/dark themes and confirm the recent-files popup still works. Tab media play/pause works; ready update state appears and `applyReadyUpdate` is invoked |
| ☐ | Sidebar close/reorder motion | `src/dao/.../sidebar/dao_flip_motion.ts`, sidebar WebUI tests | — | Closing, moving, pinning, and foldering tabs animates surviving rows without duplicate placeholders or stale transforms |

Expand Down
10 changes: 6 additions & 4 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ An Arc-inspired vertical sidebar replaces Chromium's top tab strip — the singl
the tab count. Pin state is serialized through a shared sequenced writer and
atomically replaces the previous profile file.
- **dao_folder_item.ts** / **dao_folder_model.ts** — Folder grouping with
profile-path persistence (load/save round-trip). Only a folder named exactly
`stale` exposes a cleanup action through a Dao native system confirmation
dialog: confirming closes only its currently matched child tabs and deletes
the folder; Cancel preserves both.
profile-path persistence (load/save round-trip). Every folder context menu
exposes Unfolder, which removes the folder and releases its child tabs in
place, and Delete Folder, which uses a Dao native system confirmation dialog
before closing the folder's currently matched child tabs. The folder is
deleted only after those tabs actually close; cancelling either confirmation
or a page's beforeunload prompt preserves the folder and remaining tabs.
- **Configurable stale-tab expiration** — The "You and Dao" Settings page
stores a profile-scoped integer from 1–720 hours (24 hours by default);
the sidebar's "Move Stale Tabs to stale" action reads that value when run,
Expand Down
22 changes: 11 additions & 11 deletions src/dao/browser/strings/dao_strings.grd
Original file line number Diff line number Diff line change
Expand Up @@ -292,23 +292,23 @@
<message name="IDS_DAO_FOLDER_CONTEXT_RENAME" desc="Context menu item that starts renaming a folder in the Dao sidebar.">
Rename
</message>
<message name="IDS_DAO_FOLDER_CONTEXT_DELETE" desc="Context menu item that deletes a folder in the Dao sidebar. Tabs inside the folder remain open.">
Delete Folder
<message name="IDS_DAO_FOLDER_CONTEXT_UNFOLDER" desc="Context menu item that removes a folder in the Dao sidebar while leaving its tabs open.">
Unfolder
</message>
<message name="IDS_DAO_FOLDER_CONTEXT_CLEAR_STALE_TABS" desc="Context menu item that starts clearing tabs from the stale folder in the Dao sidebar.">
Clear Stale Tabs
<message name="IDS_DAO_FOLDER_CONTEXT_DELETE" desc="Context menu item that starts deleting a folder and closing every tab inside it.">
Delete Folder
</message>
<message name="IDS_DAO_CLEAR_STALE_TABS_DIALOG_TITLE" desc="Title of the confirmation dialog shown before clearing every tab from the stale folder.">
Clear stale tabs?
<message name="IDS_DAO_DELETE_FOLDER_DIALOG_TITLE" desc="Title of the confirmation dialog shown before deleting a Dao sidebar folder and closing its tabs.">
Delete folder?
</message>
<message name="IDS_DAO_CLEAR_STALE_TABS_DIALOG_DESCRIPTION" desc="Description in the confirmation dialog explaining that clearing stale tabs closes the tabs and deletes the stale folder.">
This will close all tabs in the stale folder and delete the folder.
<message name="IDS_DAO_DELETE_FOLDER_DIALOG_DESCRIPTION" desc="Description in the confirmation dialog explaining that deleting a folder closes every tab inside it.">
This will close all tabs in the folder and delete the folder.
</message>
<message name="IDS_DAO_CLEAR_STALE_TABS_DIALOG_CANCEL" desc="Label on the button that cancels clearing stale tabs.">
<message name="IDS_DAO_DELETE_FOLDER_DIALOG_CANCEL" desc="Label on the button that cancels deleting a folder.">
Cancel
</message>
<message name="IDS_DAO_CLEAR_STALE_TABS_DIALOG_CONFIRM" desc="Label on the destructive confirmation button that clears stale tabs.">
Clear
<message name="IDS_DAO_DELETE_FOLDER_DIALOG_CONFIRM" desc="Label on the destructive confirmation button that deletes a folder and closes its tabs.">
Delete
</message>

<!-- Command bar -->
Expand Down
8 changes: 4 additions & 4 deletions src/dao/browser/strings/translations/dao_strings_zh-CN.xtb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<translationbundle lang="zh-CN">
<translation id="1173894706177603556">重命名</translation>
<translation id="1293177648337752319">取消网站静音</translation>
<translation id="1349314697251468085">这会关闭文件夹中的所有标签并删除该文件夹。</translation>
<translation id="1602287703039480507">已清除此网站缓存</translation>
<translation id="1653598257495639807">二维码扫描结果</translation>
<translation id="1809939268435598390">删除文件夹</translation>
Expand All @@ -15,17 +16,16 @@
<translation id="3007771295016901659">复制标签页</translation>
<translation id="3062877722240966678">Dao i18n 管线正常</translation>
<translation id="3249579521706735875">该功能仅在系统深色模式下生效</translation>
<translation id="3420663750132400268">删除文件夹?</translation>
<translation id="3435738964857648380">安全</translation>
<translation id="3450492919008172498">没有新的标签页被归档</translation>
<translation id="3551320343578183772">关闭标签页</translation>
<translation id="35564291038608079">清除过期标签页?</translation>
<translation id="3657099196021255130">在 Dao 中打开</translation>
<translation id="3708693288863478389">输入网址或搜索...</translation>
<translation id="385051799172605136">返回</translation>
<translation id="3891466792657071243">停止加载</translation>
<translation id="3901975710974642844">将过期标签页移动到“过期”</translation>
<translation id="3984237987235889323">应用中</translation>
<translation id="4029402916766829056">这将关闭“过期”文件夹中的所有标签页,并删除该文件夹。</translation>
<translation id="4201242995651540725">已归档过去24小时未活动的标签页</translation>
<translation id="4285498937028063278">取消固定</translation>
<translation id="4322394346347055525">关闭其他标签页</translation>
Expand All @@ -42,10 +42,8 @@
<translation id="5556459405103347317">重新加载</translation>
<translation id="5611474372949142946">关闭下方标签页</translation>
<translation id="5953452567010839148">未找到二维码</translation>
<translation id="6007071648771993435">清除过期标签页</translation>
<translation id="6042308850641462728">更多</translation>
<translation id="6100906629904366438">This is a legacy (Manifest V2) extension. Dao supports it; Chrome and most other browsers no longer do.</translation>
<translation id="6643016212128521049">清除</translation>
<translation id="6736243959894955139">地址</translation>
<translation id="6829876854799051628">清除 Cookie</translation>
<translation id="6896758677409633944">复制</translation>
Expand All @@ -55,7 +53,9 @@
<translation id="7604253494819481181">再次按<ph name="SHORTCUT" />切换侧边栏</translation>
<translation id="7658239707568436148">取消</translation>
<translation id="7717845620320228976">检查更新</translation>
<translation id="7974106569409739809">解散文件夹</translation>
<translation id="8137559199583651773">管理扩展</translation>
<translation id="8261506727792406068">删除</translation>
<translation id="8572586736757116553"><ph name="ARROW" /> 返回</translation>
<translation id="8717864919010420084">复制链接</translation>
<translation id="9144412711146411188">已归档不活跃的标签</translation>
Expand Down
36 changes: 29 additions & 7 deletions src/dao/browser/ui/views/dao_browser_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
#include "content/public/test/download_test_observer.h"
#include "content/public/test/slow_download_http_response.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_web_ui.h"
#include "dao/browser/agent/dao_agent_memory_service.h"
#include "dao/browser/agent/dao_agent_memory_service_factory.h"
#include "dao/browser/agent/dao_agent_memory_store.h"
Expand Down Expand Up @@ -743,6 +744,11 @@ void AttachSidebarHandlerForTesting(Browser* browser,
handler->SetBrowser(browser);
}

class TestDaoSidebarUIHandler : public DaoSidebarUIHandler {
public:
using DaoSidebarUIHandler::set_web_ui;
};

class CountingDialogDelegate : public views::DialogDelegate {
public:
CountingDialogDelegate() {
Expand Down Expand Up @@ -1952,28 +1958,44 @@ IN_PROC_BROWSER_TEST_F(DaoSidebarBrowserTest, CloseTabsByStableIdentity) {
}

IN_PROC_BROWSER_TEST_F(DaoSidebarBrowserTest,
ClearStaleTabsUsesDaoNativeDialog) {
DaoSidebarUIHandler handler;
DeleteFolderUsesDaoNativeDialog) {
content::TestWebUI web_ui;
TestDaoSidebarUIHandler handler;
handler.set_web_ui(&web_ui);
AttachSidebarHandlerForTesting(browser(), &handler);
handler.AllowJavascriptForTesting();
web_ui.ClearTrackedCalls();

views::Widget* widget =
handler.ShowClearStaleTabsDialogForTesting("stale-folder");
handler.ShowDeleteFolderDialogForTesting("folder-id");
ScopedWidgetCloser close_widget(widget);
ASSERT_NE(nullptr, widget);
EXPECT_TRUE(widget->IsVisible());

views::DialogDelegate* dialog = widget->widget_delegate()->AsDialogDelegate();
ASSERT_NE(nullptr, dialog);
EXPECT_TRUE(dialog->use_dao_system_dialog_style());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_DAO_CLEAR_STALE_TABS_DIALOG_TITLE),
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_DAO_DELETE_FOLDER_DIALOG_TITLE),
dialog->GetWindowTitle());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_DAO_CLEAR_STALE_TABS_DIALOG_CONFIRM),
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_DAO_DELETE_FOLDER_DIALOG_CONFIRM),
dialog->GetDialogButtonLabel(ui::mojom::DialogButton::kOk));
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_DAO_CLEAR_STALE_TABS_DIALOG_CANCEL),
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_DAO_DELETE_FOLDER_DIALOG_CANCEL),
dialog->GetDialogButtonLabel(ui::mojom::DialogButton::kCancel));
EXPECT_TRUE(HasDescendantLabelText(
dialog->GetContentsView(),
l10n_util::GetStringUTF16(IDS_DAO_CLEAR_STALE_TABS_DIALOG_DESCRIPTION)));
l10n_util::GetStringUTF16(IDS_DAO_DELETE_FOLDER_DIALOG_DESCRIPTION)));

dialog->AcceptDialog();

ASSERT_EQ(1u, web_ui.call_data().size());
const content::TestWebUI::CallData& call = *web_ui.call_data().front();
EXPECT_EQ("cr.webUIListenerCallback", call.function_name());
ASSERT_NE(nullptr, call.arg1());
ASSERT_NE(nullptr, call.arg2());
ASSERT_NE(nullptr, call.arg3());
EXPECT_EQ("folderContextMenuCommand", call.arg1()->GetString());
EXPECT_EQ("folder-id", call.arg2()->GetString());
EXPECT_EQ("deleteConfirmed", call.arg3()->GetString());
}

IN_PROC_BROWSER_TEST_F(DaoSidebarBrowserTest,
Expand Down
Loading
Loading